diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 5e5990a1..ceae4583 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -1,72 +1,73 @@ name: PR Build on: [pull_request] jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18] - steps: - - uses: FranzDiebold/github-env-vars-action@v2 - - uses: actions/checkout@v1 - - name: Check cache - id: cache - uses: actions/cache@v1 - with: - path: packages/sdk/node_modules - key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}-0 - restore-keys: | - ${{ runner.os }}-node- - - name: Use Node ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - registry-url: 'https://npm.pkg.github.com' - scope: '@chili-publish' - - name: install dependencies - run: yarn install - env: - NODE_AUTH_TOKEN: ${{ secrets.PACKAGE_SECRET }} - - name: run license check - run: yarn validate-licenses - - name: run linting - run: yarn ci-lint - - name: run tests - run: yarn cover - - name: Publish Unit Test Results - continue-on-error: true - uses: EnricoMi/publish-unit-test-result-action@v1 - if: always() - with: - files: packages/sdk/coverage/**/*.xml - - name: build code - run: yarn build - - name: ensure packages/sdk/upload exists - run: node cicd.js sdk mkdir -p upload/dev-packages/$CI_PR_ID - - name: pack sdk build - run: node cicd.js sdk yarn pack -f upload/dev-packages/$CI_PR_ID/studio-sdk.tgz - - name: prepare for connectors upload - run: node cicd.js connectors yarn prepare-upload - - name: copy file branch - run: | - path=packages/sdk/upload/coverage/$CI_REF_NAME && mkdir -p ${path%"/merge"} && cp -R packages/sdk/coverage/lcov-report/index.html packages/sdk/coverage/lcov-report/coverage.html && - cp -R packages/sdk/coverage/lcov-report/src packages/sdk/coverage/lcov-report/coverage.html packages/sdk/coverage/lcov-report/base.css packages/sdk/coverage/lcov-report/prettify.css ${path%"/merge"} - - name: Copy to Azure Blob Storage - uses: azure/CLI@v1 - with: - inlineScript: | - az storage blob upload-batch -d sdk -s packages/sdk/upload/ --connection-string "${{ secrets.AZURE_CDN_STUDIO_DEV_CONNECTION_STRING }}" --overwrite true - - name: Copy to Azure Blob Storage (Connectors) - uses: azure/CLI@v1 - with: - inlineScript: | - az storage blob upload-batch -d sdk -s packages/connectors/upload/ --connection-string "${{ secrets.AZURE_CDN_STUDIO_DEV_CONNECTION_STRING }}" --overwrite true - - name: prepare for actions upload - run: | - node cicd.js actions node scripts/prepare-release.mjs - - name: Copy to Azure Blob Storage (Actions) - uses: azure/CLI@v1 - with: - inlineScript: | - az storage blob upload-batch -d sdk -s packages/actions/cdn/ --connection-string "${{ secrets.AZURE_CDN_STUDIO_DEV_CONNECTION_STRING }}" --overwrite true - + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18] + steps: + - uses: FranzDiebold/github-env-vars-action@v2 + - uses: actions/checkout@v4 + - name: Check cache + id: cache + uses: actions/cache@v1 + with: + path: packages/sdk/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}-0 + restore-keys: | + ${{ runner.os }}-node- + - name: Use Node ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + registry-url: "https://npm.pkg.github.com" + scope: "@chili-publish" + - name: install dependencies + run: yarn install + env: + NODE_AUTH_TOKEN: ${{ secrets.PACKAGE_SECRET }} + - name: run license check + run: yarn validate-licenses + - name: run linting + run: yarn ci-lint + - name: run tests + run: yarn cover + - name: Publish Unit Test Results + continue-on-error: true + uses: EnricoMi/publish-unit-test-result-action@v1 + if: always() + with: + files: packages/sdk/coverage/**/*.xml + - name: build code + run: yarn build + - name: validate sdk examples + run: cd examples/sdk/basic-typescript-example && npm install && npm run build + - name: ensure packages/sdk/upload exists + run: node cicd.js sdk mkdir -p upload/dev-packages/$CI_PR_ID + - name: pack sdk build + run: node cicd.js sdk yarn pack -f upload/dev-packages/$CI_PR_ID/studio-sdk.tgz + - name: prepare for connectors upload + run: node cicd.js connectors yarn prepare-upload + - name: copy file branch + run: | + path=packages/sdk/upload/coverage/$CI_REF_NAME && mkdir -p ${path%"/merge"} && cp -R packages/sdk/coverage/lcov-report/index.html packages/sdk/coverage/lcov-report/coverage.html && + cp -R packages/sdk/coverage/lcov-report/src packages/sdk/coverage/lcov-report/coverage.html packages/sdk/coverage/lcov-report/base.css packages/sdk/coverage/lcov-report/prettify.css ${path%"/merge"} + - name: Copy to Azure Blob Storage + uses: azure/CLI@v1 + with: + inlineScript: | + az storage blob upload-batch -d sdk -s packages/sdk/upload/ --connection-string "${{ secrets.AZURE_CDN_STUDIO_DEV_CONNECTION_STRING }}" --overwrite true + - name: Copy to Azure Blob Storage (Connectors) + uses: azure/CLI@v1 + with: + inlineScript: | + az storage blob upload-batch -d sdk -s packages/connectors/upload/ --connection-string "${{ secrets.AZURE_CDN_STUDIO_DEV_CONNECTION_STRING }}" --overwrite true + - name: prepare for actions upload + run: | + node cicd.js actions node scripts/prepare-release.mjs + - name: Copy to Azure Blob Storage (Actions) + uses: azure/CLI@v1 + with: + inlineScript: | + az storage blob upload-batch -d sdk -s packages/actions/cdn/ --connection-string "${{ secrets.AZURE_CDN_STUDIO_DEV_CONNECTION_STRING }}" --overwrite true diff --git a/.github/workflows/pr-comment-on-open.yml b/.github/workflows/pr-comment-on-open.yml index b72a7d1f..8d5e8081 100644 --- a/.github/workflows/pr-comment-on-open.yml +++ b/.github/workflows/pr-comment-on-open.yml @@ -1,21 +1,21 @@ name: PR Comment on: - pull_request: - types: [opened] + pull_request: + types: [opened] jobs: - comment: - runs-on: ubuntu-latest - steps: - - uses: FranzDiebold/github-env-vars-action@v2 - - uses: actions/checkout@v1 - - name: 'Comment on PR' - uses: actions/github-script@0.3.0 - if: github.event_name == 'pull_request' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { issue: { number: issue_number }, repo: { owner, repo } } = context; - const fs = require('fs'); - const template = fs.readFileSync('.github/pull_request_comment_template.md', 'utf8'); - const comment = template.replaceAll('<>', issue_number); - github.issues.createComment({ issue_number, owner, repo, body: comment }); \ No newline at end of file + comment: + runs-on: ubuntu-latest + steps: + - uses: FranzDiebold/github-env-vars-action@v2 + - uses: actions/checkout@v4 + - name: "Comment on PR" + uses: actions/github-script@0.3.0 + if: github.event_name == 'pull_request' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { issue: { number: issue_number }, repo: { owner, repo } } = context; + const fs = require('fs'); + const template = fs.readFileSync('.github/pull_request_comment_template.md', 'utf8'); + const comment = template.replaceAll('<>', issue_number); + github.issues.createComment({ issue_number, owner, repo, body: comment }); diff --git a/.github/workflows/pr-merge.yml b/.github/workflows/pr-merge.yml index 2572f274..75fc1cc2 100644 --- a/.github/workflows/pr-merge.yml +++ b/.github/workflows/pr-merge.yml @@ -10,7 +10,7 @@ jobs: matrix: node-version: [18] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: token: ${{ secrets.PACKAGE_SECRET }} - name: Check cache diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 39282492..e55e592f 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -2,65 +2,65 @@ name: Publish Docs on: - # Runs when released - release: - types: [released] + # Runs when released + release: + types: [released] - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: - contents: read - pages: write - id-token: write + contents: read + pages: write + id-token: write # Allow one concurrent deployment concurrency: - group: 'pages' - cancel-in-progress: true + group: "pages" + cancel-in-progress: true jobs: - # Single deploy job since we're just deploying - deploy_to_pages: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Check cache - id: cache - uses: actions/cache@v1 - with: - path: packages/sdk/node_modules - key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}-0 - restore-keys: | - ${{ runner.os }}-node- - - name: Use Node ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - registry-url: 'https://npm.pkg.github.com' - scope: '@chili-publish' - - name: install dependencies - run: yarn install - env: - NODE_AUTH_TOKEN: ${{ secrets.PACKAGE_SECRET }} - - name: build documentation to md - run: yarn build-docs-md - - name: build documentation to html - run: yarn build-docs-html - - name: Setup Pages - uses: actions/configure-pages@v2 - - name: Upload artifact - uses: actions/upload-pages-artifact@v1 - with: - path: './packages/sdk/docs/html' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v1 + # Single deploy job since we're just deploying + deploy_to_pages: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Check cache + id: cache + uses: actions/cache@v1 + with: + path: packages/sdk/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}-0 + restore-keys: | + ${{ runner.os }}-node- + - name: Use Node ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + registry-url: "https://npm.pkg.github.com" + scope: "@chili-publish" + - name: install dependencies + run: yarn install + env: + NODE_AUTH_TOKEN: ${{ secrets.PACKAGE_SECRET }} + - name: build documentation to md + run: yarn build-docs-md + - name: build documentation to html + run: yarn build-docs-html + - name: Setup Pages + uses: actions/configure-pages@v2 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: "./packages/sdk/docs/html" + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 diff --git a/.github/workflows/publish-release-npm.yml b/.github/workflows/publish-release-npm.yml index 63b339f3..9e6cffe4 100644 --- a/.github/workflows/publish-release-npm.yml +++ b/.github/workflows/publish-release-npm.yml @@ -9,7 +9,7 @@ jobs: matrix: node-version: [18] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: token: ${{ secrets.PACKAGE_SECRET }} - name: Check cache diff --git a/.gitignore b/.gitignore index 9e172a2b..35167951 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ lib/ lib-esm/ _bundles/ coverage/ -docs/ \ No newline at end of file +docs/ + +examples/**/package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index df63e65b..bd291784 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build PR](https://github.com/chili-publish/studio-sdk/actions/workflows/pr-merge.yml/badge.svg)](https://github.com/chili-publish/studio-sdk/actions/workflows/pr-merge.yml) [![Publish Package](https://github.com/chili-publish/studio-sdk/actions/workflows/publish-release-npm.yml/badge.svg)](https://github.com/chili-publish/studio-sdk/actions/workflows/publish-package.yml) -This is the Open Source GraFx Studio SDK which will make your life easier when you’re working on and integrating GraFx Studio. +This is the Open Source GraFx Studio SDK which you'll need while working on and integrating GraFx Studio. The project is currently under active development, contributions are welcome in the form of [creating issues](https://github.com/chili-publish/studio-sdk/issues/new/choose) or in the form of actual contributions on the code. See our [CONTRIBUTING.md](https://github.com/chili-publish/studio-sdk/blob/develop/CONTRIBUTING.md) file to get started on your first contribution. @@ -14,9 +14,6 @@ The project is currently under active development, contributions are welcome in [Link to the official SDK documentation on GitHub](https://chili-publish.github.io/studio-sdk/)\* -[Link to Studio UI, a live integration example](https://github.com/chili-publish/studio-ui) - - \*Note: the hosted documentation is always based on the latest version. To get the documentation of the release that you use, you can download the sourcecode of that release and open `/docs/index.html`. ## Overview @@ -55,8 +52,8 @@ Then you can easily import the SDK in your JS and TS files, but also the typing ```typescript // TS example -import EditorSDK from '@chili-publish/studio-sdk'; -import type { Variable } from '@chili-publish/studio-sdk'; +import StudioSDK from "@chili-publish/studio-sdk"; +import type { Variable } from "@chili-publish/studio-sdk"; ``` ### Load script @@ -67,8 +64,13 @@ The other way would be to include the sdk using the script tag just before the c ``` -To really get started, there is a nice guide on [the official documentation page](https://chili-publish.github.io/studio-sdk/). -And you can find basic integration examples in [one of our other repositories](https://github.com/chili-publish/studio-sdk-integration-examples). +To really get started, or to get inspiration, these are examples of live integrations. + +[Link to some basic example integrations in JS and TS](https://github.com/chili-publish/studio-sdk/tree/main/examples/sdk) + +[Link to Studio UI, a live advanced integration example used in production (My Projects in CHILI GraFx)](https://github.com/chili-publish/studio-ui)\* + +\* Studio UI itself can also be integrated and might be exactly what you need, with almost no effort. ## Contribute? @@ -80,4 +82,4 @@ If you have any feedback on the technical parts of the application, a feature re ## License -This project is [MIT licensed](https://github.com/chili-publish/studio-sdk/blob/main/LICENSE) \ No newline at end of file +This project is [MIT licensed](https://github.com/chili-publish/studio-sdk/blob/main/LICENSE) diff --git a/examples/sdk/basic-javascript-example/README.md b/examples/sdk/basic-javascript-example/README.md new file mode 100644 index 00000000..57a44e0c --- /dev/null +++ b/examples/sdk/basic-javascript-example/README.md @@ -0,0 +1,15 @@ +# Basic Vanilla Javascript SDK example + +In this example, the SDK gets initialised in the most simple form. +It loads in the SDK via a packagemanager. This could be either `npm` or `yarn`. + +simply run `npm install @chili-publish/studio-sdk --save` and you're good to go. + +\*\* note that this example uses a local reference to the package so that needs to be changed first + +## How to run + +This basic application should be run inside a local webserver like Apache, NGINX or MAMP. +Otherwise there might be some issues regarding fetching the document and so on. + +Apart from that, it's just a matter of opening up the html file, since this is a vanilla JS example, there is no need to build or transpile anything. diff --git a/examples/sdk/basic-javascript-example/assets/styles/main.css b/examples/sdk/basic-javascript-example/assets/styles/main.css new file mode 100644 index 00000000..92f39795 --- /dev/null +++ b/examples/sdk/basic-javascript-example/assets/styles/main.css @@ -0,0 +1,68 @@ +body { + font-family: arial, sans-serif; +} + +.page-title { + font-size: 2.5rem; + background-color: #ff0048; + text-align: center; + padding: 1rem 0; + color: white; +} + +.container { + width: 100%; + height: 70vh; +} + +.editor-container { + width: 100%; + height: 100%; + min-height: 100%; +} + +.editor-container iframe { + height: 100%; + min-height: 100%; +} + +.buttons-container { + padding: 0 2rem; + margin-top: 1rem; +} + +.panels-container { + display: flex; + flex-direction: row; + padding: 0 2rem; + margin: 1rem 0; + justify-content: space-between; +} + +.layout-item { + cursor: pointer; + padding: 0.5rem 1rem; + margin-left: 0.5rem; + margin-top: 2px; + border: 1px solid black; + text-align: center; +} + +.layout-item.selected { + background-color: #ff0048; + color: white; + border-color: #ff0048; +} + +.layout-item:hover { + background-color: black; + color: white; +} + +.left-panel { + width: 75%; +} + +.right-panel { + width: 25%; +} diff --git a/examples/sdk/basic-javascript-example/assets/styles/reset.css b/examples/sdk/basic-javascript-example/assets/styles/reset.css new file mode 100644 index 00000000..45a05ecf --- /dev/null +++ b/examples/sdk/basic-javascript-example/assets/styles/reset.css @@ -0,0 +1,129 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/examples/sdk/basic-javascript-example/index.html b/examples/sdk/basic-javascript-example/index.html new file mode 100644 index 00000000..9ea88cbb --- /dev/null +++ b/examples/sdk/basic-javascript-example/index.html @@ -0,0 +1,103 @@ + + + + + + + Basic Integrator Demo | CHILI publish + + + + +

Basic Integrator Demo | CHILI publish

+
+ +
+ +
+
+ + + + +
+
+ +
+
+
+
+

Frame content

+
+ + +
+
+ + +
+
+
+

Frame layout

+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+
+
+

Layouts

+
    + +
+
+
+
+
+
+ + + + + diff --git a/examples/sdk/basic-javascript-example/integration.js b/examples/sdk/basic-javascript-example/integration.js new file mode 100644 index 00000000..a2cc96a4 --- /dev/null +++ b/examples/sdk/basic-javascript-example/integration.js @@ -0,0 +1,140 @@ +const STUDIO_DOCUMENT = `{"selectedLayoutId":"0","sdkVersion":"1.6.2","engineVersion":"1.4.1","documentVersion":"0.3.3","properties":{"type":"template"},"pages":[{"id":"0","number":0,"frames":[{"id":"1","name":"Frame 1","shapeProperties":{"enableFill":true,"fillColor":{"color":{"r":255,"g":154,"b":154,"type":"rgb"},"opacity":1,"type":"local"},"enableStroke":true,"strokeWeight":1000,"strokeColor":{"color":{"r":0,"g":0,"b":0,"type":"rgb"},"type":"local"},"allCornersSame":true},"type":"shape","src":{"type":"rectangle","cornerRadius":{"type":"none"}},"blendMode":"normal","constrainProportions":false},{"id":"2","name":"Q","type":"text","constrainProportions":false,"textContent":[{"type":"paragraph"},{"type":"span"},{"text":"How do you greet a programmer who is learning a new language?","type":"text"}],"paddingLeft":0,"paddingTop":0,"paddingRight":0,"paddingBottom":0,"numberOfColumns":1,"columnGap":5000,"textDirection":"leftToRight","flowDirection":"horizontal","verticalAlign":"middle","textStroke":false,"textStrokeWeight":1000,"textStrokeColor":0,"hasClippingPath":false,"blendMode":"normal"},{"id":"3","name":"A","type":"text","constrainProportions":false,"textContent":[{"type":"paragraph","style":{"textAlign":"center"}},{"type":"span"},{"text":"Hello, worldinhabbitant","type":"text"}],"paddingLeft":0,"paddingTop":0,"paddingRight":0,"paddingBottom":0,"numberOfColumns":1,"columnGap":5000,"textDirection":"leftToRight","flowDirection":"horizontal","verticalAlign":"middle","textStroke":false,"textStrokeWeight":1000,"textStrokeColor":0,"hasClippingPath":false,"blendMode":"normal"}]}],"layouts":[{"id":"0","name":"Default","frameProperties":[{"id":"1","x":10000,"y":10000,"width":280000,"height":180000,"rotationDegrees":0,"rotationOriginY":0,"scaleX":1,"scaleY":1,"isVisible":true,"fitMode":"fill","type":"top","minCopyfitting":0.1,"maxCopyfitting":10,"enableCopyfitting":false},{"id":"2","x":20000,"y":19000,"width":260000,"height":160000,"rotationDegrees":0,"rotationOriginY":0,"scaleX":1,"scaleY":1,"isVisible":true,"fitMode":"fill","type":"top","minCopyfitting":0.1,"maxCopyfitting":10,"enableCopyfitting":true},{"id":"3","x":20000,"y":19000,"width":260000,"height":160000,"rotationDegrees":0,"rotationOriginY":0,"scaleX":1,"scaleY":1,"isVisible":true,"fitMode":"fill","type":"top","minCopyfitting":0.1,"maxCopyfitting":10,"enableCopyfitting":true}],"width":300000,"height":200000,"childLayouts":[],"type":"top","frameAnimations":[{"id":"1","from":0,"to":5000,"basicAnimations":{}},{"id":"2","from":0,"to":2500,"basicAnimations":{"outro":{"from":1500,"to":2500,"ease":"noEase","styles":{"slide":{"direction":"right","offsetPercent":100}}}}},{"id":"3","from":2500,"to":5000,"basicAnimations":{"intro":{"from":0,"to":1000,"ease":"noEase","styles":{"slide":{"direction":"left","offsetPercent":100}}}}}],"timelineLengthMs":5000,"unit":"px","intent":"digitalAnimated","fillColor":{"color":{"r":255,"g":255,"b":255,"type":"rgb"},"opacity":1,"type":"local"}}],"stylekit":{"colors":[],"characterStyles":[],"paragraphStyles":[],"fontFamilies":[]},"variables":[],"connectors":[{"id":"grafx-media","name":"GraFx Media","source":{"source":"local","url":"grafx-media.json"},"options":{},"mappings":[]},{"id":"grafx-fonts","name":"GraFx Fonts","source":{"source":"local","url":"grafx-fonts.json"},"options":{},"mappings":[]}],"actions":[]}`; + +let SELECTED_LAYOUT_ID; + +// Initialise SDK +const SDK = new StudioSDK.default({ + onLayoutsChanged: (layouts) => { + onLayoutsChanged(layouts); + }, + onSelectedLayoutIdChanged: (id) => { + onSelectedLayoutChanged(id); + }, + onSelectedFrameLayoutChanged: (selectedFrameLayout) => { + onFrameLayoutChange(selectedFrameLayout); + }, + onSelectedFrameContentChanged: (selectedFrameContent) => { + onFrameContentChange(selectedFrameContent); + }, + onSelectedToolChanged: (tool) => { + onToolChanged(tool); + }, + editorId: "chili-editor-example", +}); + +const zoomToPage = async () => { + const zoomParams = { + pageId: null, + left: 0, + top: 0, + width: Math.floor( + document.getElementsByTagName("iframe")?.[0]?.getBoundingClientRect() + .width + ), + height: Math.floor( + document.getElementsByTagName("iframe")?.[0]?.getBoundingClientRect() + .height + ), + }; + + await SDK.canvas.zoomToPage( + zoomParams.pageId, + zoomParams.left, + zoomParams.top, + zoomParams.width, + zoomParams.height + ); +}; + +// Initialise editor +SDK.loadEditor(); + +// Load document +const loadDocument = async () => { + await SDK.document.load(STUDIO_DOCUMENT); + zoomToPage(); +}; +loadDocument(); + +// Tool selection and change +const useSelectTool = () => { + SDK.tool.setSelect(); +}; + +const useHandTool = () => { + SDK.tool.setHand(); +}; + +const useZoomTool = () => { + SDK.tool.setZoom(); +}; + +const onToolChanged = (tool) => { + if (tool) { + const toolLabel = document.getElementById("toolLabel"); + toolLabel.textContent = "Selected tool: " + tool; + } +}; + +// Play animation +const playAnimation = async () => { + SDK.animation.play(); +}; + +// Functions on frame selection +const onFrameContentChange = (selectedFrameContent) => { + if (selectedFrameContent) { + const frameTitleInput = document.getElementById("frameTitle"); + frameTitleInput.setAttribute("value", selectedFrameContent.name); + + const frameTypeInput = document.getElementById("frameType"); + frameTypeInput.setAttribute("value", selectedFrameContent.type); + } +}; +const onFrameLayoutChange = (selectedFrameLayout) => { + if (selectedFrameLayout) { + const frameXInput = document.getElementById("frameX"); + frameXInput.setAttribute("value", selectedFrameLayout.x.value); + + const frameYInput = document.getElementById("frameY"); + frameYInput.setAttribute("value", selectedFrameLayout.y.value); + + const frameWidthInput = document.getElementById("frameWidth"); + frameWidthInput.setAttribute("value", selectedFrameLayout.width.value); + + const frameHeightInput = document.getElementById("frameHeight"); + frameHeightInput.setAttribute("value", selectedFrameLayout.height.value); + } +}; + +// Select a layout +const onLayoutClick = (id) => { + SDK.layout.select(id); +}; +// Function on when a layout has been changed +const onLayoutsChanged = (layouts) => { + if (layouts && layouts.length) { + const listContainer = document.getElementById("layoutList"); + // Empty list on rerender + listContainer.innerHTML = ""; + + // loop all layouts and render them + add dynamic onClick handler + layouts.map((layout) => { + const item = document.createElement("li"); + item.setAttribute("class", "layout-item"); + if (layout.id === SELECTED_LAYOUT_ID) { + item.classList = `${item.classList} selected`; + } + item.setAttribute("id", layout.id); + item.setAttribute("onclick", `onLayoutClick('${layout.id}')`); + const itemText = document.createTextNode(layout.name); + item.appendChild(itemText); + listContainer.appendChild(item); + }); + } +}; + +const onSelectedLayoutChanged = (id) => { + console.log(`Selected layout: ${id}`); + SELECTED_LAYOUT_ID = id; +}; diff --git a/examples/sdk/basic-javascript-example/package.json b/examples/sdk/basic-javascript-example/package.json new file mode 100644 index 00000000..fc86b564 --- /dev/null +++ b/examples/sdk/basic-javascript-example/package.json @@ -0,0 +1,14 @@ +{ + "name": "basic-javascript-example", + "version": "1.0.0", + "description": "This is a basic example integration of the @chili-publish/studio-sdk package with TS and NPM (yarn)", + "main": "integration.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "@chili-publish", + "license": "MIT", + "dependencies": { + "@chili-publish/studio-sdk": "../../../packages/sdk" + } +} diff --git a/examples/sdk/basic-typescript-example/README.md b/examples/sdk/basic-typescript-example/README.md new file mode 100644 index 00000000..4c0a9810 --- /dev/null +++ b/examples/sdk/basic-typescript-example/README.md @@ -0,0 +1,46 @@ +# Basic TypeScript and NPM example of SDK usage + +This basic example shows how simple it is to make a TypeScript integration, as well as using the SDK via NPM instead of a script. + +## How to run + +### Prerequisites + +- npm or yarn +- a webserver to serve your application + +### Install dependencies + +First of all install the SDK with the packagemanager of your preference. Both NPM and Yarn are supported. + +```bash +npm install +``` + +or + +```bash +yarn install +``` + +These commands will install all necessary dependencies (in this case only SDK is needed) as well as the necessary dev-dependencies to build the example. + +### Build the project + +After all necessary dependencies are installed, the project can be built using webpack (installed as devdependency). + +```bash +npm run build +``` + +or + +```bash +yarn build +``` + +### Checkout the build + +The same goes for this example as for the vanilla JS example. The application is best run in a local webserver such as Apache, NGINX or MAMP/LAMP/XAMP/... +This way we ensure all functionalities are available that the application needs to load in the document and connect to the editor-engine. +The index.html file loads in the builded and transpiled index.js file in the /build folder. diff --git a/examples/sdk/basic-typescript-example/assets/styles/main.css b/examples/sdk/basic-typescript-example/assets/styles/main.css new file mode 100644 index 00000000..92f39795 --- /dev/null +++ b/examples/sdk/basic-typescript-example/assets/styles/main.css @@ -0,0 +1,68 @@ +body { + font-family: arial, sans-serif; +} + +.page-title { + font-size: 2.5rem; + background-color: #ff0048; + text-align: center; + padding: 1rem 0; + color: white; +} + +.container { + width: 100%; + height: 70vh; +} + +.editor-container { + width: 100%; + height: 100%; + min-height: 100%; +} + +.editor-container iframe { + height: 100%; + min-height: 100%; +} + +.buttons-container { + padding: 0 2rem; + margin-top: 1rem; +} + +.panels-container { + display: flex; + flex-direction: row; + padding: 0 2rem; + margin: 1rem 0; + justify-content: space-between; +} + +.layout-item { + cursor: pointer; + padding: 0.5rem 1rem; + margin-left: 0.5rem; + margin-top: 2px; + border: 1px solid black; + text-align: center; +} + +.layout-item.selected { + background-color: #ff0048; + color: white; + border-color: #ff0048; +} + +.layout-item:hover { + background-color: black; + color: white; +} + +.left-panel { + width: 75%; +} + +.right-panel { + width: 25%; +} diff --git a/examples/sdk/basic-typescript-example/assets/styles/reset.css b/examples/sdk/basic-typescript-example/assets/styles/reset.css new file mode 100644 index 00000000..45a05ecf --- /dev/null +++ b/examples/sdk/basic-typescript-example/assets/styles/reset.css @@ -0,0 +1,129 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/examples/sdk/basic-typescript-example/index.html b/examples/sdk/basic-typescript-example/index.html new file mode 100644 index 00000000..9cbfb99c --- /dev/null +++ b/examples/sdk/basic-typescript-example/index.html @@ -0,0 +1,102 @@ + + + + + + + Basic Integrator Demo | CHILI publish + + + + +

Basic Integrator Demo | CHILI publish

+
+ +
+ +
+
+ + + + +
+
+ +
+
+
+
+

Frame content

+
+ + +
+
+ + +
+
+
+

Frame layout

+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+
+
+

Layouts

+
    + +
+
+
+
+
+
+ + + + diff --git a/examples/sdk/basic-typescript-example/package.json b/examples/sdk/basic-typescript-example/package.json new file mode 100644 index 00000000..12cd1e53 --- /dev/null +++ b/examples/sdk/basic-typescript-example/package.json @@ -0,0 +1,22 @@ +{ + "name": "editor-integration-example-ts-npm", + "version": "0.0.1", + "description": "This is a basic example integration of the @chili-publish/studio-sdk package with TS and NPM (yarn)", + "main": "index.js", + "repository": "https://github.com/chili-publish/editor-sdk-integration-examples", + "author": "chili-publish", + "license": "MIT", + "private": false, + "dependencies": { + "@chili-publish/studio-sdk": "../../../packages/sdk" + }, + "devDependencies": { + "ts-loader": "^9.2.8", + "typescript": "^4.6.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2" + }, + "scripts": { + "build": "webpack" + } +} diff --git a/examples/sdk/basic-typescript-example/src/app.ts b/examples/sdk/basic-typescript-example/src/app.ts new file mode 100644 index 00000000..81706263 --- /dev/null +++ b/examples/sdk/basic-typescript-example/src/app.ts @@ -0,0 +1,38 @@ +import integration from "./integration"; + +class App { + constructor() { + const zoomButton = document.getElementById("zoom"); + if (zoomButton) { + zoomButton.addEventListener("click", (e: Event) => + integration.useZoomTool() + ); + } + + const selectButton = document.getElementById("select"); + if (selectButton) { + selectButton.addEventListener("click", (e: Event) => + integration.useSelectTool() + ); + } + + const handButton = document.getElementById("hand"); + if (handButton) { + handButton.addEventListener("click", (e: Event) => + integration.useHandTool() + ); + } + + const playButton = document.getElementById("play"); + if (playButton) { + playButton.addEventListener("click", (e: Event) => + integration.playAnimation() + ); + } + } +} + +// Instantiate the class when the window loads +window.onload = () => { + new App(); +}; diff --git a/examples/sdk/basic-typescript-example/src/integration.ts b/examples/sdk/basic-typescript-example/src/integration.ts new file mode 100644 index 00000000..9420e97a --- /dev/null +++ b/examples/sdk/basic-typescript-example/src/integration.ts @@ -0,0 +1,168 @@ +const STUDIO_DOCUMENT = `{"selectedLayoutId":"0","sdkVersion":"1.6.2","engineVersion":"1.4.1","documentVersion":"0.3.3","properties":{"type":"template"},"pages":[{"id":"0","number":0,"frames":[{"id":"1","name":"Frame 1","shapeProperties":{"enableFill":true,"fillColor":{"color":{"r":255,"g":154,"b":154,"type":"rgb"},"opacity":1,"type":"local"},"enableStroke":true,"strokeWeight":1000,"strokeColor":{"color":{"r":0,"g":0,"b":0,"type":"rgb"},"type":"local"},"allCornersSame":true},"type":"shape","src":{"type":"rectangle","cornerRadius":{"type":"none"}},"blendMode":"normal","constrainProportions":false},{"id":"2","name":"Q","type":"text","constrainProportions":false,"textContent":[{"type":"paragraph"},{"type":"span"},{"text":"How do you greet a programmer who is learning a new language?","type":"text"}],"paddingLeft":0,"paddingTop":0,"paddingRight":0,"paddingBottom":0,"numberOfColumns":1,"columnGap":5000,"textDirection":"leftToRight","flowDirection":"horizontal","verticalAlign":"middle","textStroke":false,"textStrokeWeight":1000,"textStrokeColor":0,"hasClippingPath":false,"blendMode":"normal"},{"id":"3","name":"A","type":"text","constrainProportions":false,"textContent":[{"type":"paragraph","style":{"textAlign":"center"}},{"type":"span"},{"text":"Hello, worldinhabbitant","type":"text"}],"paddingLeft":0,"paddingTop":0,"paddingRight":0,"paddingBottom":0,"numberOfColumns":1,"columnGap":5000,"textDirection":"leftToRight","flowDirection":"horizontal","verticalAlign":"middle","textStroke":false,"textStrokeWeight":1000,"textStrokeColor":0,"hasClippingPath":false,"blendMode":"normal"}]}],"layouts":[{"id":"0","name":"Default","frameProperties":[{"id":"1","x":10000,"y":10000,"width":280000,"height":180000,"rotationDegrees":0,"rotationOriginY":0,"scaleX":1,"scaleY":1,"isVisible":true,"fitMode":"fill","type":"top","minCopyfitting":0.1,"maxCopyfitting":10,"enableCopyfitting":false},{"id":"2","x":20000,"y":19000,"width":260000,"height":160000,"rotationDegrees":0,"rotationOriginY":0,"scaleX":1,"scaleY":1,"isVisible":true,"fitMode":"fill","type":"top","minCopyfitting":0.1,"maxCopyfitting":10,"enableCopyfitting":true},{"id":"3","x":20000,"y":19000,"width":260000,"height":160000,"rotationDegrees":0,"rotationOriginY":0,"scaleX":1,"scaleY":1,"isVisible":true,"fitMode":"fill","type":"top","minCopyfitting":0.1,"maxCopyfitting":10,"enableCopyfitting":true}],"width":300000,"height":200000,"childLayouts":[],"type":"top","frameAnimations":[{"id":"1","from":0,"to":5000,"basicAnimations":{}},{"id":"2","from":0,"to":2500,"basicAnimations":{"outro":{"from":1500,"to":2500,"ease":"noEase","styles":{"slide":{"direction":"right","offsetPercent":100}}}}},{"id":"3","from":2500,"to":5000,"basicAnimations":{"intro":{"from":0,"to":1000,"ease":"noEase","styles":{"slide":{"direction":"left","offsetPercent":100}}}}}],"timelineLengthMs":5000,"unit":"px","intent":"digitalAnimated","fillColor":{"color":{"r":255,"g":255,"b":255,"type":"rgb"},"opacity":1,"type":"local"}}],"stylekit":{"colors":[],"characterStyles":[],"paragraphStyles":[],"fontFamilies":[]},"variables":[],"connectors":[{"id":"grafx-media","name":"GraFx Media","source":{"source":"local","url":"grafx-media.json"},"options":{},"mappings":[]},{"id":"grafx-fonts","name":"GraFx Fonts","source":{"source":"local","url":"grafx-fonts.json"},"options":{},"mappings":[]}],"actions":[]}`; + +let SELECTED_LAYOUT_ID: string; + +import StudioSDK, { Frame } from "@chili-publish/studio-sdk"; +import type { + FrameLayoutType, + LayoutListItemType, + ToolType, +} from "@chili-publish/studio-sdk"; + +// Initialise SDK +const SDK = new StudioSDK({ + onLayoutsChanged: (layouts) => { + onLayoutsChanged(layouts); + }, + onSelectedLayoutIdChanged: (id) => { + onSelectedLayoutChanged(id); + }, + onSelectedFrameLayoutChanged: (selectedFrameLayout) => { + onFrameLayoutChange(selectedFrameLayout); + }, + onSelectedFrameContentChanged: (selectedFrameContent) => { + onFrameContentChange(selectedFrameContent); + }, + onSelectedToolChanged: (tool) => { + onToolChanged(tool); + }, + editorId: "chili-editor-example", +}); + +const zoomToPage = async () => { + const zoomParams: { + pageId: null; + left: number; + top: number; + width: number; + height: number; + } = { + pageId: null, + left: 0, + top: 0, + width: Math.floor( + document.getElementsByTagName("iframe")?.[0]?.getBoundingClientRect() + .width + ), + height: Math.floor( + document.getElementsByTagName("iframe")?.[0]?.getBoundingClientRect() + .height + ), + }; + + await SDK.canvas.zoomToPage( + zoomParams.pageId, + zoomParams.left, + zoomParams.top, + zoomParams.width, + zoomParams.height + ); +}; + +// Initialize editor +SDK.loadEditor(); + +// Load document +const loadDocument = async () => { + await SDK.document.load(STUDIO_DOCUMENT); + zoomToPage(); +}; +loadDocument(); + +// Tool selection and change available on window +const useSelectTool = () => { + SDK.tool.setSelect(); +}; + +const useHandTool = () => { + SDK.tool.setHand(); +}; + +const useZoomTool = () => { + SDK.tool.setZoom(); +}; + +const onToolChanged = (tool: ToolType) => { + if (tool) { + const toolLabel = document.getElementById("toolLabel"); + toolLabel.textContent = "Selected tool: " + tool; + } +}; + +// Play animation +const playAnimation = async () => { + SDK.animation.play(); +}; + +// Functions on frame selection +const onFrameContentChange = (selectedFrameContent: Frame) => { + if (selectedFrameContent) { + const frameTitleInput = document.getElementById("frameTitle"); + frameTitleInput.setAttribute("value", selectedFrameContent.name); + + const frameTypeInput = document.getElementById("frameType"); + frameTypeInput.setAttribute("value", selectedFrameContent.type); + } +}; +const onFrameLayoutChange = (selectedFrameLayout: FrameLayoutType) => { + if (selectedFrameLayout) { + const frameXInput = document.getElementById("frameX"); + frameXInput.setAttribute("value", String(selectedFrameLayout.x.value)); + + const frameYInput = document.getElementById("frameY"); + frameYInput.setAttribute("value", String(selectedFrameLayout.y.value)); + + const frameWidthInput = document.getElementById("frameWidth"); + frameWidthInput.setAttribute( + "value", + String(selectedFrameLayout.width.value) + ); + + const frameHeightInput = document.getElementById("frameHeight"); + frameHeightInput.setAttribute( + "value", + String(selectedFrameLayout.height.value) + ); + } +}; + +// Select a layout +const onLayoutClick = (id: string) => { + SDK.layout.select(id); +}; +// Function on when a layout has been changed +const onLayoutsChanged = (layouts: LayoutListItemType[]) => { + if (layouts && layouts.length) { + const listContainer = document.getElementById("layoutList"); + // Empty list on rerender + listContainer.innerHTML = ""; + + // loop all layouts and render them + add dynamic onClick handler + layouts.map((layout) => { + const item = document.createElement("li"); + item.setAttribute("class", "layout-item"); + if (layout.id === SELECTED_LAYOUT_ID) { + //@ts-ignore + item.classList = `${item.classList} selected`; + } + item.setAttribute("id", `layout ${layout.id} ${layout.name}`); + item.onclick = () => onLayoutClick(layout.id); + const itemText = document.createTextNode(layout.name); + item.appendChild(itemText); + listContainer.appendChild(item); + }); + } +}; + +const onSelectedLayoutChanged = (id: string) => { + console.log(`Selected layout: ${id}`); + SELECTED_LAYOUT_ID = id; +}; + +export default { + useSelectTool, + useHandTool, + useZoomTool, + playAnimation, + onLayoutClick, +}; diff --git a/examples/sdk/basic-typescript-example/tsconfig.json b/examples/sdk/basic-typescript-example/tsconfig.json new file mode 100644 index 00000000..b5962dc7 --- /dev/null +++ b/examples/sdk/basic-typescript-example/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "outDir": "./build/", + "noImplicitAny": true, + "module": "es6", + "target": "es5", + "allowJs": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "sourceMap": true, + "resolveJsonModule": true + } +} diff --git a/examples/sdk/basic-typescript-example/webpack.config.js b/examples/sdk/basic-typescript-example/webpack.config.js new file mode 100644 index 00000000..5480405b --- /dev/null +++ b/examples/sdk/basic-typescript-example/webpack.config.js @@ -0,0 +1,22 @@ +const path = require("path"); + +module.exports = { + entry: "./src/app.ts", + devtool: "source-map", + module: { + rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: [".ts", ".js"], + }, + output: { + filename: "index.js", + path: path.resolve(__dirname, "build"), + }, +}; diff --git a/packages/sdk/editor-engine.json b/packages/sdk/editor-engine.json index 48c364cb..1437c8bc 100644 --- a/packages/sdk/editor-engine.json +++ b/packages/sdk/editor-engine.json @@ -1,3 +1,3 @@ { - "current": "1.4.0" + "current": "1.4.1" } diff --git a/packages/sdk/src/controllers/ToolController.ts b/packages/sdk/src/controllers/ToolController.ts index f60865c6..83b5b37d 100644 --- a/packages/sdk/src/controllers/ToolController.ts +++ b/packages/sdk/src/controllers/ToolController.ts @@ -37,56 +37,65 @@ export class ToolController { }; /** - * This method sets the used tool to a Pointer tool + * @deprecated + * This method sets the used tool to the select tool. + * This method is deprecated in favour of the setSelect tool setter. */ setPointer = async () => { return this.setTool(ToolType.SELECT); }; /** - * This method sets the used tool to a Move tool + * This method sets the used tool to the select tool. + */ + setSelect = async () => { + return this.setTool(ToolType.SELECT); + }; + + /** + * This method sets the used tool to the Move tool */ setHand = async () => { return this.setTool(ToolType.HAND); }; /** - * This method sets the used tool to a Zoom tool + * This method sets the used tool to the Zoom tool */ setZoom = async () => { return this.setTool(ToolType.ZOOM); }; /** - * This method sets the used tool to a TextFrame tool + * This method sets the used tool to the TextFrame tool */ setTextFrame = async () => { return this.setTool(ToolType.TEXT_FRAME); }; /** - * This method sets the used tool to a ImageFrame tool + * This method sets the used tool to the ImageFrame tool */ setImageFrame = async () => { return this.setTool(ToolType.IMAGE_FRAME); }; /** - * This method sets the used tool to a ShapeRectangle tool + * This method sets the used tool to the ShapeRectangle tool */ setShapeRect = async () => { return this.setTool(ToolType.SHAPE_RECT); }; /** - * This method sets the used tool to a ShapeEllipse tool + * This method sets the used tool to the ShapeEllipse tool */ setShapeEllipse = async () => { return this.setTool(ToolType.SHAPE_ELLIPSE); }; /** - * This method sets the used tool to a ShapePolygon tool + * This method sets the used tool to the ShapePolygon tool */ setShapePolygon = async () => { return this.setTool(ToolType.SHAPE_POLYGON); diff --git a/packages/sdk/webpack.config.js b/packages/sdk/webpack.config.js index 84f53389..513ed736 100644 --- a/packages/sdk/webpack.config.js +++ b/packages/sdk/webpack.config.js @@ -8,7 +8,7 @@ module.exports = (env) => ({ path: path.resolve(__dirname, '_bundles'), filename: '[name].js', libraryTarget: 'umd', - library: 'ChiliEditorSDK', + library: 'StudioSDK', umdNamedDefine: true, globalObject: 'this', }, @@ -48,11 +48,13 @@ module.exports = (env) => ({ ], optimization: { minimize: true, - minimizer: [new TerserPlugin({ - terserOptions: { - mangle: false - } - })], + minimizer: [ + new TerserPlugin({ + terserOptions: { + mangle: false, + }, + }), + ], }, devtool: 'source-map', });