-
Notifications
You must be signed in to change notification settings - Fork 37
[WXP-4953] Launch code playground (script mode) from samples in the documentation site #143
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
base: main
Are you sure you want to change the base?
Changes from 22 commits
6882b33
0871428
f4c4b8e
ec5921b
1238d48
92b1197
1de1e8e
6c97cc9
baa9f13
6f36f4f
bf1a9a4
12d4fbd
0ee3820
f610db1
5b0af58
6941828
d00726a
1fd6c8b
9164074
d5dcaa0
73369af
65103da
96ce604
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,7 +125,7 @@ jobs: | |
- name: Build site | ||
uses: borales/actions-yarn@v3 | ||
with: | ||
cmd: build | ||
cmd: build:deploy | ||
env: | ||
PREFIX_PATHS: true # equivalent to --prefix-paths flag for 'gatsby build' | ||
PATH_PREFIX: ${{ needs.set-state.outputs.path_prefix }} | ||
|
@@ -152,6 +152,12 @@ jobs: | |
GATSBY_FEDS_PRIVACY_ID: ${{ secrets.AIO_FEDS_PRIVACY_ID }} | ||
GATSBY_SITE_DOMAIN_URL: https://developer-stage.adobe.com | ||
NODE_OPTIONS: "--max_old_space_size=8192" | ||
IMS_BASE_URL: "https://ims-na1-stg1.adobelogin.com" | ||
FFC_BASE_URL: "https://ffc-addon-stage.adobe.io/" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the product instance only. |
||
PLAYGROUND_CLIENT_ID: ${{ secrets.PLAYGROUND_CLIENT_ID }} | ||
PLAYGROUND_CLIENT_SECRET: ${{ secrets.PLAYGROUND_CLIENT_SECRET }} | ||
PLAYGROUND_AUTH_CODE: ${{ secrets.PLAYGROUND_AUTH_CODE }} | ||
PLAYGROUND_API_KEY: ${{ secrets.PLAYGROUND_API_KEY }} | ||
- name: Deploy | ||
uses: AdobeDocs/static-website-deploy@master | ||
with: | ||
|
@@ -229,7 +235,7 @@ jobs: | |
- name: Build site | ||
uses: borales/actions-yarn@v3 | ||
with: | ||
cmd: build | ||
cmd: build:deploy | ||
env: | ||
PREFIX_PATHS: true # equivalent to --prefix-paths flag for 'gatsby build' | ||
PATH_PREFIX: ${{ needs.set-state.outputs.path_prefix }} | ||
|
@@ -259,6 +265,13 @@ jobs: | |
GATSBY_FEDS_PRIVACY_ID: ${{ secrets.AIO_FEDS_PRIVACY_ID }} | ||
GATSBY_SITE_DOMAIN_URL: https://developer.adobe.com | ||
NODE_OPTIONS: "--max_old_space_size=8192" | ||
IMS_BASE_URL: "https://ims-na1.adobelogin.com" | ||
FFC_BASE_URL: "https://ffc-addon.adobe.io/" | ||
# TODO: Replace with prod credentials | ||
PLAYGROUND_CLIENT_ID: ${{ secrets.PLAYGROUND_CLIENT_ID }} | ||
PLAYGROUND_CLIENT_SECRET: ${{ secrets.PLAYGROUND_CLIENT_SECRET }} | ||
PLAYGROUND_AUTH_CODE: ${{ secrets.PLAYGROUND_AUTH_CODE }} | ||
PLAYGROUND_API_KEY: ${{ secrets.PLAYGROUND_API_KEY }} | ||
- name: Deploy | ||
uses: AdobeDocs/static-website-deploy@master | ||
with: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,10 @@ | |
}, | ||
"dependencies": { | ||
"@adobe/gatsby-theme-aio": "^4.15.1", | ||
"dotenv": "17.2.2", | ||
"fs-extra": "11.3.2", | ||
"gatsby": "4.22.0", | ||
"jszip": "3.10.1", | ||
"react": "^17.0.2", | ||
"react-dom": "^17.0.2" | ||
}, | ||
|
@@ -27,12 +30,14 @@ | |
"dev": "gatsby develop", | ||
"dev:https": "gatsby develop --https --host localhost.corp.adobe.com --port 9000", | ||
"build": "gatsby build", | ||
"build:deploy": "gatsby build && yarn run postbuild", | ||
|
||
"serve": "gatsby serve", | ||
"clean": "gatsby clean", | ||
"test:links": "remark src/pages --quiet --frail", | ||
"test:lint": "./node_modules/.bin/markdownlint --config .github/linters/.markdownlint.yml src", | ||
"fix:lint": "./node_modules/.bin/markdownlint --config .github/linters/.markdownlint.yml src --fix", | ||
"lint": "docker run --rm -e RUN_LOCAL=true --env-file '.github/super-linter.env' -v \"$PWD\":/tmp/lint github/super-linter:slim-v4.10.1" | ||
"lint": "docker run --rm -e RUN_LOCAL=true --env-file '.github/super-linter.env' -v \"$PWD\":/tmp/lint github/super-linter:slim-v4.10.1", | ||
"postbuild": "node upload-playground-samples.mjs" | ||
}, | ||
"remarkConfig": { | ||
"plugins": [ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
/* | ||
* Copyright 2025 Adobe. All rights reserved. | ||
* This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. You may obtain a copy | ||
* of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under | ||
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
* OF ANY KIND, either express or implied. See the License for the specific language | ||
* governing permissions and limitations under the License. | ||
*/ | ||
|
||
import "@spectrum-css/typography"; | ||
import "@spectrum-css/tooltip"; | ||
import "@adobe/prism-adobe"; | ||
import { ActionButton } from "@adobe/gatsby-theme-aio/src/components/ActionButton"; | ||
|
||
import React, { useState } from "react"; | ||
import nextId from "react-id-generator"; | ||
import classNames from "classnames"; | ||
import Highlight, { defaultProps } from "prism-react-renderer"; | ||
import PropTypes from "prop-types"; | ||
import Prism from "prism-react-renderer/prism"; | ||
|
||
import "./styles.css"; | ||
|
||
const EXPRESS_PROD_URL = "https://express.adobe.com/new"; | ||
const CODE_PLAYGROUND_MODE = "playground"; | ||
const CODE_PLAYGROUND_SESSION = "new"; | ||
|
||
(typeof global !== "undefined" ? global : window).Prism = Prism; | ||
|
||
const getLoader = require("prismjs/dependencies"); | ||
const components = require("prismjs/components"); | ||
|
||
const componentsToLoad = [ | ||
|
||
"java", | ||
"php", | ||
"csharp", | ||
"kotlin", | ||
"swift", | ||
"bash", | ||
"sql", | ||
"typescript", | ||
"objectivec", | ||
"yaml", | ||
"json", | ||
]; | ||
const loadedComponents = ["clike", "javascript"]; | ||
|
||
// dynamically load all the prism language components | ||
const loader = getLoader(components, componentsToLoad, loadedComponents); | ||
try { | ||
loader.load((id) => { | ||
require(`prismjs/components/prism-${id}.min.js`); | ||
}); | ||
} catch (error) { | ||
console.warn(error); | ||
} | ||
|
||
// show/hide copy tooltip | ||
const showCopyTooltip = (setShouldShowCopyTooltip) => { | ||
setShouldShowCopyTooltip(true); | ||
setTimeout(() => { | ||
setShouldShowCopyTooltip(false); | ||
}, 3000); | ||
}; | ||
|
||
// copy to clipboard | ||
const copyToClipboard = async (codeContent, setIsTooltipOpen) => { | ||
await navigator.clipboard.writeText(codeContent); | ||
showCopyTooltip(setIsTooltipOpen); | ||
}; | ||
|
||
// open code playground | ||
const openCodePlayground = (codeContent, sampleId) => { | ||
const url = new URL(EXPRESS_PROD_URL); | ||
url.searchParams.set("mode", CODE_PLAYGROUND_MODE); | ||
url.searchParams.set("session", CODE_PLAYGROUND_SESSION); | ||
url.searchParams.set("sessionId", sampleId); | ||
url.searchParams.set("executionMode", "script"); | ||
window.open(url.toString(), "_blank"); | ||
}; | ||
|
||
// parse language, try option and id. | ||
// usage: ```js{try id=createRectangle} | ||
function parseAttributes(className, metastring) { | ||
const cls = String(className || ""); | ||
const meta = String(metastring || ""); | ||
|
||
// Extract language | ||
const langMatch = cls.match(/language-([^\s{]+)/); | ||
const language = langMatch ? langMatch[1].trim() : ""; | ||
|
||
// Check if "try" is present in the class string | ||
const shouldShowTry = /\btry\b/.test(`${cls} ${meta}`); | ||
|
||
// Extract id if present | ||
const idMatch = | ||
meta.match(/\bid\s*=\s*([^}\s]+)/) || cls.match(/\bid\s*=\s*([^}\s]+)/); | ||
const sampleId = idMatch ? idMatch[1].trim() : ""; | ||
|
||
return { language, shouldShowTry, sampleId }; | ||
} | ||
|
||
const Code = ({ children, className = "", theme, metastring = "" }) => { | ||
const [tooltipId] = useState(nextId); | ||
const [shouldShowCopyTooltip, setShouldShowCopyTooltip] = useState(false); | ||
|
||
const { language, shouldShowTry, sampleId } = parseAttributes( | ||
className, | ||
metastring | ||
); | ||
|
||
return ( | ||
<Highlight | ||
{...defaultProps} | ||
code={children} | ||
language={language} | ||
theme={undefined} | ||
> | ||
{({ className, tokens, getLineProps, getTokenProps }) => { | ||
const isEmptyItem = (token) => | ||
token && token.length === 1 && token[0].empty; | ||
const lines = isEmptyItem(tokens[tokens.length - 1]) | ||
? tokens.slice(0, -1) | ||
: tokens; | ||
const isMultiLine = lines.length > 1; | ||
|
||
return ( | ||
<div className={`spectrum--${theme} code-container`}> | ||
{/* Copy Button */} | ||
<ActionButton | ||
className={classNames( | ||
"spectrum-ActionButton", | ||
"code-action-button", | ||
"code-copy-button", | ||
{ "with-try": shouldShowTry } | ||
)} | ||
aria-describedby={tooltipId} | ||
onClick={() => | ||
copyToClipboard(children, setShouldShowCopyTooltip) | ||
} | ||
> | ||
Copy | ||
</ActionButton> | ||
|
||
{/* Try Button */} | ||
{shouldShowTry && ( | ||
<ActionButton | ||
className="spectrum-ActionButton code-action-button code-try-button" | ||
onClick={() => openCodePlayground(children, sampleId)} | ||
> | ||
Try | ||
</ActionButton> | ||
)} | ||
|
||
<div | ||
className={classNames("code-tooltip-container", { | ||
"with-try": shouldShowTry, | ||
})} | ||
> | ||
<span | ||
role="tooltip" | ||
id={tooltipId} | ||
className={classNames( | ||
"spectrum-Tooltip spectrum-Tooltip--left code-tooltip", | ||
{ "is-open": shouldShowCopyTooltip } | ||
)} | ||
> | ||
<span className="spectrum-Tooltip-label"> | ||
Copied to your clipboard | ||
</span> | ||
<span className="spectrum-Tooltip-tip" /> | ||
</span> | ||
</div> | ||
|
||
<pre | ||
className={classNames( | ||
className, | ||
"spectrum-Code spectrum-Code--sizeM code-pre" | ||
)} | ||
> | ||
{lines.map((line, i) => { | ||
const { style: lineStyle, ...lineProps } = getLineProps({ | ||
line, | ||
key: i, | ||
}); | ||
|
||
return ( | ||
<div key={i} className="code-line"> | ||
{isMultiLine && ( | ||
<span | ||
data-pseudo-content={i + 1} | ||
className="code-line-number" | ||
/> | ||
)} | ||
<span | ||
{...lineProps} | ||
style={lineStyle} | ||
className="code-line-content" | ||
> | ||
{/* styling the tokens in the line */} | ||
{line.map((token, key) => { | ||
const { style: tokenStyle, ...tokenProps } = | ||
getTokenProps({ token, key }); | ||
return ( | ||
<span key={key} {...tokenProps} style={tokenStyle} /> | ||
); | ||
})} | ||
</span> | ||
</div> | ||
); | ||
})} | ||
</pre> | ||
</div> | ||
); | ||
}} | ||
</Highlight> | ||
); | ||
}; | ||
|
||
Code.propTypes = { | ||
theme: PropTypes.oneOf(["light", "dark"]), | ||
}; | ||
|
||
export { Code }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
.code-container { | ||
position: relative; | ||
max-width: calc(100vw - var(--spectrum-global-dimension-size-800)); | ||
} | ||
|
||
.code-pre { | ||
padding-top: var(--spectrum-global-dimension-size-400) !important; | ||
} | ||
|
||
.code-line { | ||
display: table-row; | ||
} | ||
|
||
.code-line-number { | ||
display: table-cell; | ||
color: var(--spectrum-global-color-gray-500); | ||
text-align: left; | ||
padding-right: var(--spectrum-global-dimension-size-200); | ||
user-select: none; | ||
} | ||
|
||
.code-line-number::before { | ||
content: attr(data-pseudo-content); | ||
} | ||
|
||
.code-line-content { | ||
margin-right: var(--spectrum-global-dimension-size-1000); | ||
} | ||
|
||
.code-action-button { | ||
position: absolute; | ||
inset-block-start: 0; | ||
border-color: var(--spectrum-actionbutton-m-border-color, var(--spectrum-alias-border-color)) !important; | ||
color: var(--spectrum-actionbutton-m-text-color, var(--spectrum-alias-text-color)) !important; | ||
padding: var(--spectrum-global-dimension-size-65); | ||
} | ||
|
||
.code-copy-button { | ||
inset-inline-end: var(--spectrum-global-dimension-size-125); | ||
} | ||
|
||
.code-copy-button.with-try { | ||
inset-inline-end: var(--spectrum-global-dimension-size-700); | ||
} | ||
|
||
.code-try-button { | ||
inset-inline-end: var(--spectrum-global-dimension-size-125); | ||
} | ||
|
||
.code-tooltip-container { | ||
position: absolute; | ||
inset-block-start: var(--spectrum-global-dimension-size-65); | ||
height: var(--spectrum-global-dimension-size-300); | ||
display: flex; | ||
align-items: center; | ||
pointer-events: none; | ||
} | ||
|
||
.code-tooltip-container:not(.with-try) { | ||
inset-inline-end: calc(var(--spectrum-global-dimension-size-125) + var(--spectrum-global-dimension-size-600) + var(--spectrum-global-dimension-size-125)); | ||
} | ||
|
||
.code-tooltip-container.with-try { | ||
inset-inline-end: calc(var(--spectrum-global-dimension-size-700) + var(--spectrum-global-dimension-size-600) + var(--spectrum-global-dimension-size-125)); | ||
} | ||
|
||
.code-tooltip { | ||
display: block; | ||
position: relative; | ||
white-space: nowrap; | ||
font-family: var(--spectrum-alias-body-text-font-family, var(--spectrum-global-font-family-base)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use stage environments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Developer docs is deployed on stage. We are planning to hand over the task of adding try tags on relevant samples to devEx team. I feel uploading samples in stage environment will help them in testing the flow.