├── .nvmrc ├── docs ├── .dockerignore ├── src │ ├── pwa-512.png │ ├── components │ │ ├── index.js │ │ ├── mdxComponents │ │ │ ├── loading.js │ │ │ ├── anchor.js │ │ │ ├── LiveProvider.js │ │ │ ├── index.js │ │ │ └── codeBlock.js │ │ ├── search │ │ │ ├── styles.js │ │ │ ├── hitComps.js │ │ │ ├── input.js │ │ │ └── index.js │ │ ├── link.js │ │ ├── theme.js │ │ ├── sidebar │ │ │ ├── treeNode.js │ │ │ ├── index.js │ │ │ └── tree.js │ │ ├── styles │ │ │ ├── Docs.js │ │ │ └── PageNavigationButtons.js │ │ ├── RightSidebar │ │ │ ├── rightSidebar.js │ │ │ └── styles.js │ │ ├── layout.js │ │ └── NextPrevious.js │ ├── custom-sw-code.js │ ├── images │ │ ├── closed.js │ │ ├── opened.js │ │ ├── facebook.inline.svg │ │ ├── help.svg │ │ ├── twitter.inline.svg │ │ └── github.svg │ ├── GithubLink.js │ ├── YoutubeEmbed.js │ ├── utils │ │ └── algolia.js │ └── html.js ├── content │ ├── themes.md │ ├── app-lifecycle.md │ ├── images │ │ ├── hook-all.png │ │ ├── sc-app-flow.png │ │ ├── hook-link-only.png │ │ ├── hook-title-qr.png │ │ ├── 15five-api-data.png │ │ ├── hook-title-link.png │ │ ├── 15five-screenshot.png │ │ ├── choate-staffbase-1.png │ │ ├── get-started-loading.png │ │ ├── get-started-quote-1.png │ │ ├── get-started-quote-2.png │ │ ├── hook-body-only-v2.png │ │ ├── hook-image-only-v2.png │ │ ├── hook-title-only-v2.png │ │ ├── sweetwater-friday-1.JPG │ │ ├── sweetwater-friday-2.JPG │ │ ├── 15five-slide-snippet.png │ │ ├── example-slide-snippet.png │ │ ├── hook-body-only-with-html.png │ │ ├── 15five-data-loader-snippet.png │ │ ├── hook-image-body-with-html.png │ │ └── example-data-loader-snippet.png │ ├── example-codebases.md │ ├── add-to-app-store.md │ ├── index.mdx │ ├── overview.md │ ├── preloading.mdx │ └── example-user-apps.md ├── .prettierrc ├── gatsby-browser.js ├── Dockerfile ├── README.md ├── .eslintrc.json ├── LICENSE ├── config.js ├── package.json ├── gatsby-config.js ├── .gitignore └── gatsby-node.js ├── examples ├── 15five-firebase-cloud-function-example │ ├── functions │ │ ├── .gitignore │ │ ├── package.json │ │ ├── index.js │ │ └── .eslintrc.json │ ├── .firebaserc │ ├── firebase.json │ └── .gitignore ├── react-firebase-example │ ├── public │ │ ├── robots.txt │ │ ├── favicon.ico │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── index.html │ ├── src │ │ ├── context │ │ │ └── ThemedStyleContext.js │ │ ├── setupTests.js │ │ ├── App.test.js │ │ ├── components │ │ │ ├── error │ │ │ │ └── ErrorMessage.js │ │ │ ├── data-loader │ │ │ │ ├── data-loader.scss │ │ │ │ └── DataLoader.js │ │ │ ├── slide-show │ │ │ │ ├── SlideShow.js │ │ │ │ ├── slide-show.scss │ │ │ │ └── Slide.js │ │ │ └── player │ │ │ │ └── ScPlayerInterface.js │ │ ├── index.css │ │ ├── reportWebVitals.js │ │ ├── App.js │ │ ├── App.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── containers │ │ │ └── AppContainer.js │ ├── .gitignore │ ├── package.json │ └── README.md ├── javascript-app │ ├── src │ │ ├── images │ │ │ └── logo.png │ │ ├── index.html │ │ ├── style.css │ │ └── index.js │ ├── .babelrc │ ├── readme.md │ ├── package.json │ └── webpack.config.js ├── typescript-app │ ├── src │ │ ├── images │ │ │ └── logo.png │ │ ├── index.html │ │ ├── style.scss │ │ └── index.ts │ ├── .babelrc │ ├── readme.md │ ├── package.json │ └── webpack.config.js ├── starting-from-webapp │ ├── src │ │ ├── images │ │ │ └── logo.png │ │ ├── index.html │ │ ├── style.scss │ │ └── index.js │ ├── .babelrc │ ├── package.json │ ├── readme.md │ └── webpack.config.js └── 15Five-firebase-webapp-example │ ├── src │ ├── assets │ │ └── 15-five-logo.png │ ├── context │ │ └── ThemedStyleContext.js │ ├── setupTests.js │ ├── containers │ │ ├── app-container.scss │ │ └── AppContainer.js │ ├── App.test.js │ ├── components │ │ ├── error │ │ │ └── ErrorMessage.js │ │ ├── data-loader │ │ │ ├── data-loader.scss │ │ │ └── DataLoader.js │ │ ├── slide-show │ │ │ ├── SlideShow.js │ │ │ ├── slide-show.scss │ │ │ └── Slide.js │ │ └── player │ │ │ └── ScPlayerInterface.js │ ├── reportWebVitals.js │ ├── index.css │ ├── App.js │ ├── App.css │ ├── index.js │ └── logo.svg │ ├── .gitignore │ ├── package.json │ └── README.md ├── package.json ├── lerna.json ├── packages ├── apps-sdk │ ├── tsconfig.json │ ├── src │ │ ├── utils │ │ │ ├── objectUtils.ts │ │ │ └── postMessage.ts │ │ ├── constants.ts │ │ ├── messages.ts │ │ └── types.ts │ ├── README.md │ ├── .eslintrc.js │ ├── CHANGELOG.md │ └── package.json └── apps-editor-sdk │ ├── tsconfig.json │ ├── src │ ├── utils │ │ ├── objectUtils.ts │ │ └── postMessage.ts │ ├── constants.ts │ ├── messages.ts │ └── types.ts │ ├── README.md │ ├── CHANGELOG.md │ ├── .eslintrc.js │ └── package.json ├── .github └── workflows │ └── deploy-docs.yml ├── readme.md └── .gitignore /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.20.4 -------------------------------------------------------------------------------- /docs/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public 3 | .cache 4 | -------------------------------------------------------------------------------- /examples/15five-firebase-cloud-function-example/functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /docs/src/pwa-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/src/pwa-512.png -------------------------------------------------------------------------------- /docs/content/themes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Themes' 3 | --- 4 | 5 | Work in progress. Coming very soon! 6 | -------------------------------------------------------------------------------- /docs/content/app-lifecycle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'App Lifecycle' 3 | --- 4 | 5 | Work in progress. Coming very soon! 6 | -------------------------------------------------------------------------------- /docs/content/images/hook-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-all.png -------------------------------------------------------------------------------- /docs/content/images/sc-app-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/sc-app-flow.png -------------------------------------------------------------------------------- /examples/react-firebase-example/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /docs/content/images/hook-link-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-link-only.png -------------------------------------------------------------------------------- /docs/content/images/hook-title-qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-title-qr.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "devDependencies": { 5 | "lerna": "^3.20.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/content/images/15five-api-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/15five-api-data.png -------------------------------------------------------------------------------- /docs/content/images/hook-title-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-title-link.png -------------------------------------------------------------------------------- /docs/content/images/15five-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/15five-screenshot.png -------------------------------------------------------------------------------- /docs/content/images/choate-staffbase-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/choate-staffbase-1.png -------------------------------------------------------------------------------- /docs/content/images/get-started-loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/get-started-loading.png -------------------------------------------------------------------------------- /docs/content/images/get-started-quote-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/get-started-quote-1.png -------------------------------------------------------------------------------- /docs/content/images/get-started-quote-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/get-started-quote-2.png -------------------------------------------------------------------------------- /docs/content/images/hook-body-only-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-body-only-v2.png -------------------------------------------------------------------------------- /docs/content/images/hook-image-only-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-image-only-v2.png -------------------------------------------------------------------------------- /docs/content/images/hook-title-only-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-title-only-v2.png -------------------------------------------------------------------------------- /docs/content/images/sweetwater-friday-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/sweetwater-friday-1.JPG -------------------------------------------------------------------------------- /docs/content/images/sweetwater-friday-2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/sweetwater-friday-2.JPG -------------------------------------------------------------------------------- /docs/src/components/index.js: -------------------------------------------------------------------------------- 1 | export mdxComponents from './mdxComponents'; 2 | export Layout from './layout'; 3 | export Link from './link'; 4 | -------------------------------------------------------------------------------- /examples/15five-firebase-cloud-function-example/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "screencloud-15five" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/javascript-app/src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/javascript-app/src/images/logo.png -------------------------------------------------------------------------------- /examples/typescript-app/src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/typescript-app/src/images/logo.png -------------------------------------------------------------------------------- /docs/content/images/15five-slide-snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/15five-slide-snippet.png -------------------------------------------------------------------------------- /docs/content/images/example-slide-snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/example-slide-snippet.png -------------------------------------------------------------------------------- /docs/content/images/hook-body-only-with-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-body-only-with-html.png -------------------------------------------------------------------------------- /docs/content/images/15five-data-loader-snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/15five-data-loader-snippet.png -------------------------------------------------------------------------------- /docs/content/images/hook-image-body-with-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/hook-image-body-with-html.png -------------------------------------------------------------------------------- /examples/react-firebase-example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/react-firebase-example/public/favicon.ico -------------------------------------------------------------------------------- /examples/react-firebase-example/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/react-firebase-example/public/logo192.png -------------------------------------------------------------------------------- /examples/react-firebase-example/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/react-firebase-example/public/logo512.png -------------------------------------------------------------------------------- /examples/starting-from-webapp/src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/starting-from-webapp/src/images/logo.png -------------------------------------------------------------------------------- /docs/content/images/example-data-loader-snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/docs/content/images/example-data-loader-snippet.png -------------------------------------------------------------------------------- /docs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "jsxBracketSameLine": false, 4 | "singleQuote": true, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /examples/15five-firebase-cloud-function-example/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "functions": { 3 | "predeploy": [ 4 | "npm --prefix \"$RESOURCE_DIR\" run lint" 5 | ] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/assets/15-five-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screencloud/developer/HEAD/examples/15Five-firebase-webapp-example/src/assets/15-five-logo.png -------------------------------------------------------------------------------- /docs/src/custom-sw-code.js: -------------------------------------------------------------------------------- 1 | workbox.routing.registerRoute( 2 | new RegExp('https:.*min.(css|js)'), 3 | workbox.strategies.staleWhileRevalidate({ 4 | cacheName: 'cdn-cache', 5 | }) 6 | ); 7 | -------------------------------------------------------------------------------- /docs/src/components/mdxComponents/loading.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const LoadingProvider = ({ ...props }) => { 4 | return
; 5 | }; 6 | 7 | export default LoadingProvider; 8 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "independent", 4 | "ignoreChanges": [ 5 | "packages/*/dist/**", 6 | "**/*.test.ts", 7 | "**/*.spec.ts", 8 | "**/test/**" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/context/ThemedStyleContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | import { DEFAULT_STYLED_THEME } from "../utils/constants"; 3 | 4 | export const ThemedStyleContext = createContext(DEFAULT_STYLED_THEME); 5 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/context/ThemedStyleContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | import { DEFAULT_STYLED_THEME } from "../utils/constants"; 3 | 4 | export const ThemedStyleContext = createContext(DEFAULT_STYLED_THEME); 5 | -------------------------------------------------------------------------------- /docs/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | export const onServiceWorkerUpdateReady = () => { 2 | const answer = window.confirm( 3 | `This tutorial has been updated. ` + 4 | `Reload to display the latest version?` 5 | ) 6 | if (answer === true) { 7 | window.location.reload() 8 | } 9 | } -------------------------------------------------------------------------------- /examples/react-firebase-example/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/containers/app-container.scss: -------------------------------------------------------------------------------- 1 | .app-container { 2 | display: flex; 3 | flex-direction: row; 4 | width: 100vw; 5 | height: 100vh; 6 | 7 | &_left { 8 | background: #FF3100; 9 | width: 30%; 10 | } 11 | 12 | &_right { 13 | width: 70%; 14 | } 15 | } -------------------------------------------------------------------------------- /examples/react-firebase-example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/components/error/ErrorMessage.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | const ErrorMessage = ({errorMessage}) => { 5 | return
6 | {errorMessage} 7 |
8 | 9 | } 10 | 11 | export default ErrorMessage; -------------------------------------------------------------------------------- /docs/src/images/closed.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ClosedSvg = () => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ClosedSvg; 10 | -------------------------------------------------------------------------------- /docs/src/images/opened.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const OpenedSvg = () => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default OpenedSvg; 10 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/components/error/ErrorMessage.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | const ErrorMessage = ({errorMessage}) => { 5 | return
6 | {errorMessage} 7 |
8 | 9 | } 10 | 11 | export default ErrorMessage; -------------------------------------------------------------------------------- /examples/javascript-app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "entry" 7 | } 8 | ] 9 | ], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { 14 | "regenerator": true 15 | } 16 | ] 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /examples/typescript-app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "entry" 7 | } 8 | ] 9 | ], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { 14 | "regenerator": true 15 | } 16 | ] 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/components/search/styles.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Algolia } from 'styled-icons/fa-brands/Algolia'; 3 | 4 | export const PoweredBy = () => ( 5 | 6 | Powered by{` `} 7 | 8 | Algolia 9 | 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /examples/starting-from-webapp/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "entry" 7 | } 8 | ] 9 | ], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { 14 | "regenerator": true 15 | } 16 | ] 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/GithubLink.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | const githubIcon = require('../../images/github.svg'); 3 | 4 | const GithubLink = ({ link, text }) => { 5 | return ( 6 | 7 | github 8 | {text} 9 | 10 | ); 11 | }; 12 | 13 | export default GithubLink; 14 | -------------------------------------------------------------------------------- /docs/src/components/mdxComponents/anchor.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const AnchorTag = ({ children: link, ...props }) => { 4 | if (link) { 5 | return ( 6 | 7 | {link} 8 | 9 | ); 10 | } else { 11 | return null; 12 | } 13 | }; 14 | 15 | export default AnchorTag; 16 | -------------------------------------------------------------------------------- /docs/src/components/link.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link as GatsbyLink } from 'gatsby'; 3 | import isAbsoluteUrl from 'is-absolute-url'; 4 | 5 | const Link = ({ to, ...props }) => 6 | isAbsoluteUrl(to) ? ( 7 | 8 | {props.children} 9 | 10 | ) : ( 11 | 12 | ); 13 | 14 | export default Link; 15 | -------------------------------------------------------------------------------- /examples/javascript-app/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ScreenCloud JS App Example 5 | 6 | 7 |
8 |

...

9 |
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/src/components/mdxComponents/LiveProvider.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live'; 3 | 4 | const ReactLiveProvider = ({ code }) => { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | }; 13 | 14 | export default ReactLiveProvider; 15 | -------------------------------------------------------------------------------- /examples/starting-from-webapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ScreenCloud JS App Example 5 | 6 | 7 |
8 |

...

9 |
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/typescript-app/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ScreenCloud TypeScript App Example 5 | 6 | 7 |
8 |

...

9 |
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/react-firebase-example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /packages/apps-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "esModuleInterop": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "jsx": "preserve", 7 | "lib": ["dom", "dom.iterable", "esnext"], 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "outDir": "lib", 11 | "strict": true, 12 | "target": "es5" 13 | }, 14 | "include": ["src"], 15 | "exclude": ["node_modules", "**/__tests__/*"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/apps-editor-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "esModuleInterop": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "jsx": "preserve", 7 | "lib": ["dom", "dom.iterable", "esnext"], 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "outDir": "lib", 11 | "strict": true, 12 | "target": "es5" 13 | }, 14 | "include": ["src"], 15 | "exclude": ["node_modules", "**/__tests__/*"] 16 | } 17 | -------------------------------------------------------------------------------- /docs/src/components/search/hitComps.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Highlight, Snippet } from 'react-instantsearch-dom'; 3 | import { Link } from 'gatsby'; 4 | 5 | export const PageHit = clickHandler => ({ hit }) => ( 6 |
7 | 8 |
9 | 10 |
11 | 12 | 13 |
14 | ); 15 | -------------------------------------------------------------------------------- /docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:buster 2 | 3 | # Create app directory 4 | WORKDIR /app 5 | 6 | # Install app dependencies 7 | # RUN npm -g install serve 8 | RUN npm -g install gatsby-cli 9 | 10 | COPY package*.json ./ 11 | 12 | RUN npm ci 13 | 14 | # Bundle app source 15 | COPY . . 16 | 17 | # Build static files 18 | RUN npm run build 19 | 20 | # serve on port 8080 21 | # CMD ["serve", "-l", "tcp://0.0.0.0:8080", "public"] 22 | CMD ["gatsby", "serve", "--verbose", "--prefix-paths", "-p", "8080", "--host", "0.0.0.0"] 23 | -------------------------------------------------------------------------------- /docs/src/YoutubeEmbed.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const YoutubeEmbed = ({ link }) => { 4 | return ( 5 |
6 | 15 |
16 | ); 17 | }; 18 | 19 | export default YoutubeEmbed; 20 | -------------------------------------------------------------------------------- /docs/src/components/theme.js: -------------------------------------------------------------------------------- 1 | export const theme = { 2 | fonts: { 3 | mono: '"SF Mono", "Roboto Mono", Menlo, monospace', 4 | }, 5 | colors: { 6 | background: '#fff', 7 | heading: '#000', 8 | text: '#3B454E', 9 | preFormattedText: 'rgb(245, 247, 249)', 10 | link: '#1000EE', 11 | scGrey: '#2d313a', 12 | scGreyDark: '#2d313a', 13 | scGreyDarker: '#24272e', 14 | scYellow: '#fecf00', 15 | scYellowLight: '#FFEE95', 16 | scYellowLighter: 'rgba(254,207,0,0.2)', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/components/data-loader/data-loader.scss: -------------------------------------------------------------------------------- 1 | .data-loader { 2 | margin: auto; 3 | margin-top: 40vh; 4 | width: 12em; 5 | 6 | .loader { 7 | border: 16px solid #f3f3f3; 8 | border-top: 16px solid #D3AC24; 9 | border-radius: 50%; 10 | width: 120px; 11 | height: 120px; 12 | animation: spin 2s linear infinite; 13 | } 14 | 15 | @keyframes spin { 16 | 0% { 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | transform: rotate(360deg); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/components/data-loader/data-loader.scss: -------------------------------------------------------------------------------- 1 | .data-loader { 2 | margin: auto; 3 | margin-top: 40vh; 4 | width: 12em; 5 | 6 | .loader { 7 | border: 16px solid #f3f3f3; 8 | border-top: 16px solid #D3AC24; 9 | border-radius: 50%; 10 | width: 120px; 11 | height: 120px; 12 | animation: spin 2s linear infinite; 13 | } 14 | 15 | @keyframes spin { 16 | 0% { 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | transform: rotate(360deg); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /docs/src/images/facebook.inline.svg: -------------------------------------------------------------------------------- 1 | Facebook icon -------------------------------------------------------------------------------- /packages/apps-sdk/src/utils/objectUtils.ts: -------------------------------------------------------------------------------- 1 | import { InitializeMessagePayload } from "../types"; 2 | 3 | /** 4 | * Combine 2 payloads, with data in newPayload replacing that in default. 5 | */ 6 | export const mergeInitializePayloads = ( 7 | defaultPayload: InitializeMessagePayload, 8 | newPayload: Partial> 9 | ): InitializeMessagePayload => { 10 | return { 11 | ...defaultPayload, 12 | ...newPayload, 13 | context: { 14 | ...defaultPayload.context, 15 | ...newPayload.context, 16 | }, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/apps-editor-sdk/src/utils/objectUtils.ts: -------------------------------------------------------------------------------- 1 | import { InitializeMessagePayload } from "../types"; 2 | 3 | /** 4 | * Combine 2 payloads, with data in newPayload replacing that in default. 5 | */ 6 | export const mergeInitializePayloads = ( 7 | defaultPayload: InitializeMessagePayload, 8 | newPayload: Partial> 9 | ): InitializeMessagePayload => { 10 | return { 11 | ...defaultPayload, 12 | ...newPayload, 13 | context: { 14 | ...defaultPayload.context, 15 | ...newPayload.context, 16 | }, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # ScreenCloud Developer Docs 2 | 3 | This is the entire site published at: [https://screencloud.github.io/developer/](https://screencloud.github.io/developer/) 4 | 5 | For questions, please contact our [Professional Services team](mailto:proservices@screencloud.io). 6 | 7 | To contribute, you're welcome to fork the repo, modify the `/docs/` folder, then submit a PR back. 8 | 9 | ## 💫 Credits 10 | 11 | The site is powered by [Gatsby](https://www.gatsbyjs.org/), and the theme is based off the [gatsby-gitbook-starter](https://github.com/hasura/gatsby-gitbook-starter) project by [Hasura](http://hasura.io/). 12 | -------------------------------------------------------------------------------- /docs/src/images/help.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | height: 100vh; 9 | width: 100vw; 10 | overflow: hidden; 11 | } 12 | 13 | code { 14 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 15 | monospace; 16 | } 17 | 18 | #root { 19 | height: 100vh; 20 | width: 100vw; 21 | overflow: hidden; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /examples/javascript-app/readme.md: -------------------------------------------------------------------------------- 1 | ## Vanilla JavaScript App Example 2 | 3 | This example is for projects built using any sort of JavaScript/HTML combo. 4 | 5 | For more specific integrations, check out the React example or raise an issue for others you'd like to see. 6 | 7 | ### How to Use 8 | 9 | - Clone the repository, then navigate to this folder. 10 | - Run `npm install` the first time. 11 | - Run `npm start` to develop locally. Your app will start on [http://localhost:8000/](http://localhost:8000/) 12 | - Run `npm run build` to make a production-optimised bundle. 13 | 14 | Feel free to open an issue with any questions! 15 | -------------------------------------------------------------------------------- /examples/typescript-app/readme.md: -------------------------------------------------------------------------------- 1 | ## Vanilla JavaScript App Example 2 | 3 | This example is for projects built using any sort of JavaScript/HTML combo. 4 | 5 | For more specific integrations, check out the React example or raise an issue for others you'd like to see. 6 | 7 | ### How to Use 8 | 9 | - Clone the repository, then navigate to this folder. 10 | - Run `npm install` the first time. 11 | - Run `npm start` to develop locally. Your app will start on [http://localhost:8000/](http://localhost:8000/) 12 | - Run `npm run build` to make a production-optimised bundle. 13 | 14 | Feel free to open an issue with any questions! 15 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/components/slide-show/SlideShow.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Slide from "./Slide"; 3 | 4 | 5 | const SlideShow = (props) => { 6 | const { data, currentSelectedIndex } = props; 7 | const currentData = data[currentSelectedIndex]; 8 | console.log(props) 9 | return ( 10 |
11 |
12 | 15 | 16 |
17 |
18 | ); 19 | }; 20 | 21 | export default SlideShow; 22 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/components/slide-show/SlideShow.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Slide from "./Slide"; 3 | 4 | 5 | const SlideShow = (props) => { 6 | const { data, currentSelectedIndex } = props; 7 | const currentData = data[currentSelectedIndex]; 8 | console.log(props) 9 | return ( 10 |
11 |
12 | 15 | 16 |
17 |
18 | ); 19 | }; 20 | 21 | export default SlideShow; 22 | -------------------------------------------------------------------------------- /examples/react-firebase-example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /examples/javascript-app/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | background: #2d313b; 8 | color: #fff; 9 | overflow: hidden; 10 | } 11 | 12 | .contents { 13 | height: 100vh; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | } 18 | 19 | .quote { 20 | font-size: 4rem; 21 | max-width: 70%; 22 | text-align: center; 23 | font-family: serif; 24 | } 25 | 26 | .small-text { 27 | font-size: 3rem; 28 | } 29 | 30 | .logo { 31 | position: fixed; 32 | left: 50%; 33 | bottom: 2rem; 34 | transform: translateX(-50%); 35 | width: 10vw; 36 | height: auto; 37 | min-width: 100px; 38 | } 39 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/App.js: -------------------------------------------------------------------------------- 1 | import logo from './logo.svg'; 2 | import './App.css'; 3 | 4 | function App() { 5 | return ( 6 |
7 |
8 | logo 9 |

10 | Edit src/App.js and save to reload. 11 |

12 | 18 | Learn React 19 | 20 |
21 |
22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /examples/typescript-app/src/style.scss: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | background: #2d313b; 8 | color: #fff; 9 | overflow: hidden; 10 | } 11 | 12 | .contents { 13 | height: 100vh; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | } 18 | 19 | .quote { 20 | font-size: 4rem; 21 | max-width: 70%; 22 | text-align: center; 23 | font-family: serif; 24 | } 25 | 26 | .small-text { 27 | font-size: 3rem; 28 | } 29 | 30 | .logo { 31 | position: fixed; 32 | left: 50%; 33 | bottom: 2rem; 34 | transform: translateX(-50%); 35 | width: 10vw; 36 | height: auto; 37 | min-width: 100px; 38 | } 39 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/App.js: -------------------------------------------------------------------------------- 1 | import logo from './logo.svg'; 2 | import './App.css'; 3 | 4 | function App() { 5 | return ( 6 |
7 |
8 | logo 9 |

10 | Edit src/App.js and save to reload. 11 |

12 | 18 | Learn React 19 | 20 |
21 |
22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /examples/starting-from-webapp/src/style.scss: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | background: #2d313b; 8 | color: #fff; 9 | overflow: hidden; 10 | } 11 | 12 | .contents { 13 | height: 100vh; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | } 18 | 19 | .quote { 20 | font-size: 4rem; 21 | max-width: 70%; 22 | text-align: center; 23 | font-family: serif; 24 | } 25 | 26 | .small-text { 27 | font-size: 3rem; 28 | } 29 | 30 | .logo { 31 | position: fixed; 32 | left: 50%; 33 | bottom: 2rem; 34 | transform: translateX(-50%); 35 | width: 10vw; 36 | height: auto; 37 | min-width: 100px; 38 | } 39 | -------------------------------------------------------------------------------- /packages/apps-sdk/README.md: -------------------------------------------------------------------------------- 1 | # ScreenCloud Apps SDK 2 | 3 | Develop your own apps for ScreenCloud. 4 | 5 | Documentation and sample code published here: [https://screencloud.github.io/developer/](https://screencloud.github.io/developer/) 6 | 7 | ## Quickstart 8 | 9 | ``` 10 | npm install @screencloud/apps-sdk 11 | ``` 12 | 13 | or 14 | 15 | ``` 16 | yarn add @screencloud/apps-sdk 17 | ``` 18 | 19 | Then in your app: 20 | 21 | ```javascript 22 | import { connectScreenCloud } from "@screencloud/apps-sdk"; 23 | 24 | const sc = await connectScreenCloud(); 25 | const appConfig = sc.getConfig(); 26 | ``` 27 | 28 | For more, check out the [Getting Started guide](https://screencloud.github.io/developer/get-started) 29 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/components/slide-show/slide-show.scss: -------------------------------------------------------------------------------- 1 | .slide { 2 | width: 200vw; 3 | background: #062726; 4 | display: flex; 5 | width: 100%; 6 | height: 100%; 7 | font-family: lato; 8 | 9 | &_holder { 10 | padding-top: 15vh; 11 | display: flex; 12 | flex-direction: column; 13 | width: 100%; 14 | 15 | &_title { 16 | font-size: 4em; 17 | padding: 1em; 18 | text-align: center; 19 | color: #b9c4c4; 20 | } 21 | 22 | &_body { 23 | font-size: 4em; 24 | padding: 1em; 25 | text-align: center; 26 | color: #ffffff; 27 | } 28 | } 29 | } 30 | 31 | .slide-show { 32 | &_holder { 33 | display: flex; 34 | height: 100vh; 35 | } 36 | } -------------------------------------------------------------------------------- /packages/apps-editor-sdk/README.md: -------------------------------------------------------------------------------- 1 | # ScreenCloud Apps SDK 2 | 3 | Develop your own apps for ScreenCloud. 4 | 5 | Documentation and sample code published here: [https://screencloud.github.io/developer/](https://screencloud.github.io/developer/) 6 | 7 | ## Quickstart 8 | 9 | ``` 10 | npm install @screencloud/apps-editor-sdk 11 | ``` 12 | 13 | or 14 | 15 | ``` 16 | yarn add @screencloud/apps-editor-sdk 17 | ``` 18 | 19 | Then in your app: 20 | 21 | ```javascript 22 | import { connectScreenCloud } from "@screencloud/apps-editor-sdk"; 23 | 24 | const sc = await connectScreenCloud(); 25 | const appConfig = sc.getConfig(); 26 | ``` 27 | 28 | For more, check out the [Getting Started guide](https://screencloud.github.io/developer/get-started) 29 | -------------------------------------------------------------------------------- /docs/src/images/twitter.inline.svg: -------------------------------------------------------------------------------- 1 | Twitter icon -------------------------------------------------------------------------------- /packages/apps-editor-sdk/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.2](https://github.com/screencloud/developer/compare/@screencloud/apps-editor-sdk@1.0.1...@screencloud/apps-editor-sdk@1.0.2) (2022-05-18) 7 | 8 | **Note:** Version bump only for package @screencloud/apps-editor-sdk 9 | 10 | 11 | 12 | 13 | 14 | ## 1.0.1 (2022-05-17) 15 | 16 | **Note:** Version bump only for package @screencloud/apps-editor-sdk 17 | 18 | ## 1.0.0 (2022-05-17) 19 | 20 | ### Features 21 | 22 | - first public release ([293c16e](https://github.com/screencloud/developer/commit/293c16e890c8e4e9c6b1f9828bba2af4868d9635)) 23 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/15five-firebase-cloud-function-example/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "lint": "eslint .", 6 | "serve": "firebase emulators:start --only functions", 7 | "shell": "firebase functions:shell", 8 | "start": "npm run shell", 9 | "deploy": "firebase deploy --only functions", 10 | "logs": "firebase functions:log" 11 | }, 12 | "engines": { 13 | "node": "12" 14 | }, 15 | "main": "index.js", 16 | "dependencies": { 17 | "firebase-admin": "^9.2.0", 18 | "firebase-functions": "^3.11.0" 19 | }, 20 | "devDependencies": { 21 | "eslint": "^5.12.0", 22 | "eslint-plugin-promise": "^4.0.1", 23 | "firebase-functions-test": "^0.2.0" 24 | }, 25 | "private": true 26 | } 27 | -------------------------------------------------------------------------------- /docs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:import/errors", 5 | "plugin:react/recommended", 6 | "plugin:jsx-a11y/recommended", 7 | "prettier", 8 | "prettier/react" 9 | ], 10 | "plugins": ["react", "import", "jsx-a11y"], 11 | "settings": { 12 | "react": { 13 | "version": "detect" 14 | } 15 | }, 16 | "rules": { 17 | "react/prop-types": 0, 18 | "react/react-in-jsx-scope": "off", 19 | "lines-between-class-members": ["error", "always"] 20 | }, 21 | "parser": "babel-eslint", 22 | "parserOptions": { 23 | "ecmaVersion": 10, 24 | "sourceType": "module", 25 | "ecmaFeatures": { 26 | "jsx": true 27 | } 28 | }, 29 | "env": { 30 | "es6": true, 31 | "browser": true, 32 | "node": true 33 | }, 34 | "globals": { 35 | "graphql": false 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import DataLoader from "./components/data-loader/DataLoader"; 5 | import reportWebVitals from './reportWebVitals'; 6 | import {ScPlayerInterface} from "./components/player/ScPlayerInterface"; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | {data => { 12 | return 13 | 14 | 15 | }} 16 | 17 | 18 | , 19 | document.getElementById('root') 20 | ); 21 | 22 | // If you want to start measuring performance in your app, pass a function 23 | // to log results (for example: reportWebVitals(console.log)) 24 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 25 | reportWebVitals(); 26 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import DataLoader from "./components/data-loader/DataLoader"; 5 | import reportWebVitals from './reportWebVitals'; 6 | import {ScPlayerInterface} from "./components/player/ScPlayerInterface"; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | {data => { 12 | return 13 | 14 | 15 | }} 16 | 17 | 18 | , 19 | document.getElementById('root') 20 | ); 21 | 22 | // If you want to start measuring performance in your app, pass a function 23 | // to log results (for example: reportWebVitals(console.log)) 24 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 25 | reportWebVitals(); 26 | -------------------------------------------------------------------------------- /docs/src/utils/algolia.js: -------------------------------------------------------------------------------- 1 | const config = require('../../config.js'); 2 | 3 | const pageQuery = `{ 4 | pages: allMdx { 5 | edges { 6 | node { 7 | objectID: id 8 | fields { 9 | slug 10 | } 11 | headings { 12 | value 13 | } 14 | frontmatter { 15 | title 16 | metaDescription 17 | } 18 | excerpt(pruneLength: 50000) 19 | } 20 | } 21 | } 22 | }`; 23 | 24 | const flatten = arr => 25 | arr.map(({ node: { frontmatter, fields, ...rest } }) => ({ 26 | ...frontmatter, 27 | ...fields, 28 | ...rest, 29 | })); 30 | 31 | const settings = { attributesToSnippet: [`excerpt:20`] }; 32 | 33 | const indexName = config.header.search ? config.header.search.indexName : ''; 34 | 35 | const queries = [ 36 | { 37 | query: pageQuery, 38 | transformer: ({ data }) => flatten(data.pages.edges), 39 | indexName: `${indexName}`, 40 | settings, 41 | }, 42 | ]; 43 | 44 | module.exports = queries; 45 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-22.04 11 | permissions: 12 | contents: write 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version-file: ".nvmrc" 20 | cache: npm 21 | cache-dependency-path: ./docs/package-lock.json 22 | 23 | - name: Install system dependencies 24 | run: | 25 | sudo apt-get update 26 | sudo apt-get install -y libvips-dev 27 | 28 | - name: Build Gatsby 29 | working-directory: ./docs 30 | run: | 31 | npm ci 32 | npm run build 33 | 34 | - name: Deploy 35 | uses: peaceiris/actions-gh-pages@v3 36 | with: 37 | github_token: ${{ secrets.GITHUB_TOKEN }} 38 | publish_dir: ./docs/public 39 | publish_branch: gh-pages 40 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/components/slide-show/Slide.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import './slide-show.scss'; 3 | 4 | /** 5 | * Slide Component - here is where you create the view for the data you fetched from server. Each slide will be shown on 6 | * on screen for the length of time you set in the AppContainer.js 7 | */ 8 | export const Slide = (props) => { 9 | const {jokeSetup, jokeAnswer} = props.data; 10 | return ( 11 |
12 |
13 |
14 | {jokeSetup} 15 |
16 |
17 | {jokeAnswer} 18 |
19 |
20 |
21 |
22 |
23 | ); 24 | }; 25 | 26 | export default memo(Slide); -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "15-five-screencloud", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@screencloud/apps-sdk": "^1.1.0", 7 | "@testing-library/jest-dom": "^5.11.4", 8 | "@testing-library/react": "^11.1.0", 9 | "@testing-library/user-event": "^12.1.10", 10 | "node-sass": "^4.14.1", 11 | "react": "^17.0.1", 12 | "react-dom": "^17.0.1", 13 | "react-scripts": "4.0.0", 14 | "superagent": "^6.1.0", 15 | "web-vitals": "^0.2.4" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /docs/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hasura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Develop Apps on ScreenCloud 2 | 3 | Published on: https://screencloud.github.io/developer/ 4 | 5 | ## Quickstart 6 | 7 | - The [Apps SDK](https://www.npmjs.com/package/@screencloud/apps-sdk) on npm. 8 | - [Example codebases](https://github.com/screencloud/developer/tree/master/examples) here in Github. 9 | - [Get Started](https://screencloud.github.io/developer/get-started) guide. 10 | 11 | ## Documentation 12 | 13 | Head to the [Overview](https://screencloud.github.io/developer/overview) for a quick intro to some key concepts, or go straight to [Get Started](https://screencloud.github.io/developer/get-started). 14 | 15 | This is still early days for our 3rd party app support. Some steps are more manual than we'd like, but we'll call them out clearly and wherever we can help, we're happy to. 16 | 17 | We'd really appreciate [your feedback](mailto:proservices@screencloud.io) on what's painful or confusing so we know where to focus our efforts next. 18 | 19 | ## Questions & Help 20 | 21 | If you have any questions or need assistance, email our [Professional Services team](mailto:proservices@screencloud.io) — we’ll be happy to help. 22 | -------------------------------------------------------------------------------- /examples/react-firebase-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-firebase-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@screencloud/apps-sdk": "^1.1.0", 7 | "@testing-library/jest-dom": "^5.11.4", 8 | "@testing-library/react": "^11.1.0", 9 | "@testing-library/user-event": "^12.1.10", 10 | "node-sass": "^4.14.1", 11 | "react": "^17.0.1", 12 | "react-dom": "^17.0.1", 13 | "react-scripts": "4.0.0", 14 | "react-transition-group": "^4.4.1", 15 | "superagent": "^5.1.0", 16 | "web-vitals": "^0.2.4" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": [ 26 | "react-app", 27 | "react-app/jest" 28 | ] 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docs/src/images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 12 | 13 | -------------------------------------------------------------------------------- /examples/react-firebase-example/src/components/player/ScPlayerInterface.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { connectScreenCloud } from '@screencloud/apps-sdk'; 3 | 4 | export class ScPlayerInterface extends Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | appStarted: false, 10 | config: null, 11 | }; 12 | } 13 | 14 | async componentDidMount() { 15 | let testData; 16 | if (process.env.NODE_ENV === "development") { 17 | testData = { 18 | config: { 19 | 20 | }, 21 | }; 22 | } 23 | const sc = await connectScreenCloud(testData); 24 | this.setState({ 25 | config: sc.getConfig(), 26 | }) 27 | 28 | sc.onAppStarted().then(() => { 29 | console.log('APP STARTED!!!') 30 | this.setState({ 31 | appStarted: true, 32 | }) 33 | }); 34 | 35 | } 36 | 37 | render() { 38 | return <> 39 | {this.props.children({appStarted: this.state.appStarted, config: this.state.config})} 40 | 41 | } 42 | } -------------------------------------------------------------------------------- /packages/apps-sdk/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Linting Rules 3 | * 4 | * We deliberately do not write our own set of rules. 5 | * Instead, we use the standard set of recommended rules for whichever tech stack an app uses. 6 | * 7 | * This should normally be a set of: 8 | * - Language rules (i.e. TS or JS) 9 | * - Framework rules (e.g. React) 10 | * - Prettier (i.e. Disable formatting rules from above in favour of prettier) 11 | * 12 | * Rule documentation: 13 | * - TS: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules 14 | * - React: https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules 15 | * - CRA: https://www.npmjs.com/package/eslint-config-react-app 16 | * - CRA enables a subset of accessibility rules from: (Use CRA link above to see which) 17 | * https://github.com/evcohen/eslint-plugin-jsx-a11y#supported-rules 18 | */ 19 | module.exports = { 20 | parser: "@typescript-eslint/parser", 21 | extends: [ 22 | "plugin:@typescript-eslint/recommended", 23 | "prettier", 24 | "prettier/@typescript-eslint", 25 | ], 26 | plugins: ["@typescript-eslint"], 27 | }; 28 | -------------------------------------------------------------------------------- /packages/apps-editor-sdk/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Linting Rules 3 | * 4 | * We deliberately do not write our own set of rules. 5 | * Instead, we use the standard set of recommended rules for whichever tech stack an app uses. 6 | * 7 | * This should normally be a set of: 8 | * - Language rules (i.e. TS or JS) 9 | * - Framework rules (e.g. React) 10 | * - Prettier (i.e. Disable formatting rules from above in favour of prettier) 11 | * 12 | * Rule documentation: 13 | * - TS: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules 14 | * - React: https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules 15 | * - CRA: https://www.npmjs.com/package/eslint-config-react-app 16 | * - CRA enables a subset of accessibility rules from: (Use CRA link above to see which) 17 | * https://github.com/evcohen/eslint-plugin-jsx-a11y#supported-rules 18 | */ 19 | module.exports = { 20 | parser: "@typescript-eslint/parser", 21 | extends: [ 22 | "plugin:@typescript-eslint/recommended", 23 | "prettier", 24 | "prettier/@typescript-eslint", 25 | ], 26 | plugins: ["@typescript-eslint"], 27 | }; 28 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/components/player/ScPlayerInterface.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { connectScreenCloud } from '@screencloud/apps-sdk'; 3 | 4 | export class ScPlayerInterface extends Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | appStarted: false, 10 | config: null, 11 | }; 12 | } 13 | 14 | async componentDidMount() { 15 | let testData; 16 | if (process.env.NODE_ENV === "development") { 17 | testData = { 18 | config: { 19 | 20 | }, 21 | }; 22 | } 23 | const sc = await connectScreenCloud(testData); 24 | this.setState({ 25 | config: sc.getConfig(), 26 | }) 27 | 28 | sc.onAppStarted().then(() => { 29 | console.log('APP STARTED!!!') 30 | this.setState({ 31 | appStarted: true, 32 | }) 33 | }); 34 | 35 | } 36 | 37 | render() { 38 | return <> 39 | {this.props.children({appStarted: this.state.appStarted, config: this.state.config})} 40 | 41 | } 42 | } -------------------------------------------------------------------------------- /packages/apps-sdk/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.2.2](https://github.com/screencloud/developer/compare/@screencloud/apps-sdk@1.1.0...@screencloud/apps-sdk@1.2.2) (2022-02-10) 7 | 8 | **Note:** Version bump only for package @screencloud/apps-sdk 9 | 10 | 11 | 12 | 13 | 14 | ## [1.2.1](https://github.com/screencloud/developer/compare/@screencloud/apps-sdk@1.1.0...@screencloud/apps-sdk@1.2.1) (2022-02-10) 15 | 16 | **Note:** Version bump only for package @screencloud/apps-sdk 17 | 18 | 19 | 20 | 21 | 22 | # [1.1.0](https://github.com/screencloud/developer/compare/@screencloud/apps-sdk@1.0.1...@screencloud/apps-sdk@1.1.0) (2020-04-27) 23 | 24 | 25 | ### Features 26 | 27 | * first public release ([245e164](https://github.com/screencloud/developer/commit/245e1644bb0fc9f10f2ce939c8a7b63fa51edca2)) 28 | 29 | 30 | 31 | 32 | 33 | ## 1.0.1 (2020-04-27) 34 | 35 | 36 | ### Bug Fixes 37 | 38 | * rename from apps-js-sdk to apps-sdk ([09db55e](https://github.com/screencloud/developer/commit/09db55e7a67dd0cf2cdaa5cbe5a1bd15f751f94c)) 39 | -------------------------------------------------------------------------------- /examples/starting-from-webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starting-from-webapp", 3 | "version": "1.0.0", 4 | "description": "The clean slate; a normal JS webapp with NPM packages that we will convert to a ScreenCloud app.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run build:prod", 8 | "build:dev": "webpack --mode development", 9 | "build:prod": "webpack --mode production", 10 | "start": "webpack-dev-server --mode development" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/screencloud/developer.git" 18 | }, 19 | "devDependencies": { 20 | "@babel/plugin-transform-runtime": "^7.18.10", 21 | "@babel/preset-env": "^7.18.10", 22 | "@babel/preset-typescript": "^7.18.6", 23 | "babel-loader": "^8.2.5", 24 | "clean-webpack-plugin": "^4.0.0", 25 | "copy-webpack-plugin": "^11.0.0", 26 | "css-loader": "^6.7.1", 27 | "html-webpack-plugin": "^5.5.0", 28 | "mini-css-extract-plugin": "^2.6.1", 29 | "sass": "^1.54.5", 30 | "sass-loader": "^13.0.2", 31 | "webpack": "^5.74.0", 32 | "webpack-cli": "^4.10.0", 33 | "webpack-dev-server": "^4.10.0" 34 | }, 35 | "browserslist": "> 0.25%, not dead" 36 | } 37 | -------------------------------------------------------------------------------- /examples/starting-from-webapp/readme.md: -------------------------------------------------------------------------------- 1 | ## Starting from a Webapp 2 | 3 | This is _not_ a ScreenCloud app yet. 4 | 5 | This project is the basis for the other `-app` examples in this folder. It is shared for anyone who wants to work along with the Getting Started guide step by step. 6 | 7 | Hopefully it should look familiar to any JavaScript app you might have worked on before. There is a `package.json` with all our dependencies, and a build tool that converts your source (in `/src/`) into standard JavaScript and HTML (in `/dist/`) 8 | 9 | We use Webpack here, but there is nothing ScreenCloud-specific in there. If you're already using Gulp, Grunt or another tool, that's no bother! You won't have to change anything there. 10 | 11 | ### How to Use 12 | 13 | - Clone the repository, then navigate to this folder. 14 | - Run `npm install` the first time. 15 | - Run `npm start` to develop locally. Your app will start on [http://localhost:8000/](http://localhost:8000/) 16 | - Run `npm run build` to make a production-optimised bundle. 17 | 18 | Feel free to open an issue with any questions! 19 | 20 | ### Notes 21 | 22 | - Has support for SASS, using the `.scss` extension. 23 | - Has support for TypeScript, using the `.ts` extension. 24 | - Images should be placed in `/src/images/`. They will then be copied to `/dist/images/` during build. 25 | -------------------------------------------------------------------------------- /examples/15Five-firebase-webapp-example/src/components/slide-show/slide-show.scss: -------------------------------------------------------------------------------- 1 | .slide { 2 | width: 200vw; 3 | background: #ffffff; 4 | display: flex; 5 | width: 100%; 6 | height: 100%; 7 | font-family: lato; 8 | 9 | &_holder { 10 | padding-top: 15vh; 11 | display: flex; 12 | flex-direction: column; 13 | width: 100%; 14 | 15 | &_title { 16 | display: flex; 17 | flex-direction: row; 18 | align-content: space-between; 19 | font-size: 2em; 20 | padding: 1em; 21 | 22 | &_text { 23 | width: 70%; 24 | font-weight: bold; 25 | padding-right: 1em; 26 | } 27 | 28 | &_date { 29 | width: 20%; 30 | background: #ff4b13; 31 | text-align: center; 32 | border-radius: 10px; 33 | font-weight: bold; 34 | color: white; 35 | font-size: .9em; 36 | line-height: 1.5em; 37 | } 38 | 39 | } 40 | 41 | &_body { 42 | font-size: 2em; 43 | padding: 1em; 44 | padding-top: 10vh; 45 | 46 | &_from { 47 | padding-bottom: 2vh; 48 | font-weight: bold; 49 | } 50 | &_text { 51 | 52 | } 53 | } 54 | 55 | &_footer { 56 | } 57 | } 58 | } 59 | 60 | .slide-show { 61 | &_holder { 62 | display: flex; 63 | height: 100vh; 64 | } 65 | } -------------------------------------------------------------------------------- /packages/apps-sdk/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { AppConfig, InitializeMessagePayload } from "./types"; 2 | 3 | // Message Types 4 | export const CONNECT = "CONNECT"; 5 | export const CONNECT_SUCCESS = "CONNECT_SUCCESS"; 6 | export const DISCONNECT = "DISCONNECT"; // Deprecated. 7 | export const INITIALIZE = "initialize"; 8 | export const INITIALIZED = "initialized"; 9 | export const START = "start"; 10 | export const STARTED = "started"; 11 | 12 | // Message "type"s which prefix their string with ___ 13 | export const LEGACY_PREFIXED_TYPES = [CONNECT, CONNECT_SUCCESS, DISCONNECT]; 14 | 15 | // Prepended to the start of each log message 16 | export const LOG_PREFIX = "[Apps SDK] "; 17 | 18 | // Default INITIALIZE payload for local dev and testing. 19 | export const SAMPLE_INITIALIZE_PAYLOAD: InitializeMessagePayload = { 20 | appId: "test-app-111", 21 | appInstanceId: "test-instance-222", 22 | config: { 23 | hello: "world", 24 | meaningOfLife: 42, 25 | }, 26 | context: { 27 | userInteractionEnabled: false, 28 | loggingLevel: 1, 29 | playerHeight: 1080, 30 | playerWidth: 1920, 31 | region: "eu", 32 | timezone: "Europe/London", 33 | appViewerToken: "", 34 | }, 35 | orgId: "org-333", 36 | spaceId: "space-444", 37 | screenId: "screen-555", 38 | device: {}, 39 | filesByAppInstanceId: { nodes: [] }, 40 | }; 41 | -------------------------------------------------------------------------------- /docs/content/example-codebases.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Example Codebases' 3 | --- 4 | 5 | Our sample apps are all hosted in the [Github repo](https://github.com/screencloud/developer). They're free to use, either to learn from or to copy and paste as the starting point for your own apps. 6 | 7 | For any issues or questions, please contact our [Professional Services team](mailto:proservices@screencloud.io). 8 | 9 | ## JavaScript Sample App 10 | 11 | [https://github.com/screencloud/developer/tree/master/examples/javascript-app](https://github.com/screencloud/developer/tree/master/examples/javascript-app) 12 | 13 | - Connects to the Player and reads a `config` value 14 | - Supports preloading by fetching the first joke in advance, but not refreshing jokes until the app is visible on screen. 15 | 16 | To use: 17 | 18 | ``` 19 | npm install 20 | npm start 21 | ``` 22 | 23 | ## TypeScript Sample App 24 | 25 | [https://github.com/screencloud/developer/tree/master/examples/typescript-app](https://github.com/screencloud/developer/tree/master/examples/typescript-app) 26 | 27 | - Connects to the Player and reads a `config` value 28 | - Config is fully typed (Look for the `AppConfig` interface in `index.ts`) 29 | - Supports preloading by fetching the first joke in advance, but not refreshing jokes until the app is visible on screen. 30 | 31 | To use: 32 | 33 | ``` 34 | npm install 35 | npm start 36 | ``` 37 | -------------------------------------------------------------------------------- /examples/javascript-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-app", 3 | "version": "1.0.0", 4 | "description": "This example is for projects built using any sort of JavaScript/HTML combo.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run build:prod", 8 | "build:dev": "webpack --mode development", 9 | "build:prod": "webpack --mode production", 10 | "start": "webpack-dev-server --mode development" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/screencloud/developer.git" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "7.9.0", 21 | "@babel/plugin-transform-runtime": "^7.9.0", 22 | "@babel/preset-env": "7.9.5", 23 | "@babel/preset-typescript": "7.9.0", 24 | "babel-loader": "8.1.0", 25 | "clean-webpack-plugin": "3.0.0", 26 | "copy-webpack-plugin": "5.1.1", 27 | "css-loader": "3.5.2", 28 | "file-loader": "6.0.0", 29 | "html-webpack-plugin": "4.2.0", 30 | "mini-css-extract-plugin": "0.9.0", 31 | "node-sass": "4.13.1", 32 | "sass-loader": "^8.0.2", 33 | "uglifyjs-webpack-plugin": "2.2.0", 34 | "webpack": "4.43.0", 35 | "webpack-cli": "3.3.11", 36 | "webpack-dev-server": "3.10.3" 37 | }, 38 | "browserslist": "> 0.25%, not dead", 39 | "dependencies": { 40 | "@screencloud/apps-sdk": "1.1.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/typescript-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-app", 3 | "version": "1.0.0", 4 | "description": "This example is for projects built using any sort of TypeScript/JS/HTML combo.", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npm run build:prod", 8 | "build:dev": "webpack --mode development", 9 | "build:prod": "webpack --mode production", 10 | "start": "webpack-dev-server --mode development" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/screencloud/developer.git" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.9.0", 21 | "@babel/plugin-transform-runtime": "^7.9.0", 22 | "@babel/preset-env": "^7.9.5", 23 | "@babel/preset-typescript": "^7.9.0", 24 | "babel-loader": "^8.1.0", 25 | "clean-webpack-plugin": "^3.0.0", 26 | "copy-webpack-plugin": "^5.1.1", 27 | "css-loader": "^3.5.2", 28 | "file-loader": "^6.0.0", 29 | "html-webpack-plugin": "^4.2.0", 30 | "mini-css-extract-plugin": "^0.9.0", 31 | "uglifyjs-webpack-plugin": "^2.2.0", 32 | "webpack": "^4.43.0", 33 | "webpack-cli": "^3.3.11", 34 | "webpack-dev-server": "^3.10.3" 35 | }, 36 | "browserslist": "> 0.25%, not dead", 37 | "dependencies": { 38 | "@screencloud/apps-sdk": "^1.2.2", 39 | "node-sass": "^7.0.3", 40 | "sass-loader": "^10.3.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docs/content/add-to-app-store.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Add to App Store' 3 | --- 4 | 5 | To run your app in Studio, you'll need to add it to the App Store. 6 | 7 | To do this, fill out either of the forms below with the details we need, and we'll add it for you asap. 8 | 9 | ## Add an App for Development 10 | 11 | If you're starting to develop a new app, you don't need to worry about all the details like screenshots and app descriptions yet. 12 | 13 | This form asks for the bare minimum to get you going, and we'll provide filler details for the rest. 14 | 15 | Click to load the [Develop an App on ScreenCloud](https://docs.google.com/forms/d/e/1FAIpQLScBlxBq-1NhQzD1v7FkjDrdLVNTq0FkwJwYgnj_IprRxH2dww/viewform) form. 16 | 17 | ## Publish an App 18 | 19 | When you've built your app (or if you knew all the details upfront in development already!), it's time to polish up the App Store tile and descriptions. 20 | 21 | Click to load the [Release an App on ScreenCloud](https://docs.google.com/forms/d/e/1FAIpQLSd-3kCft7L_5MHorzzLYN5CFEwsK0bNVlRDwp8FvR1w4FgDsg/viewform) form. 22 | 23 | For questions about what any of these questions mean, feel free to get in touch any time. 24 | 25 | ## Making Updates 26 | 27 | As you host the app yourself, you can push code updates at any time. 28 | 29 | To update the details provided on the forms above any time, it's no problem. You can reply to the message we sent after adding your app with your changes, and we'll make them in no time. 30 | -------------------------------------------------------------------------------- /examples/starting-from-webapp/src/index.js: -------------------------------------------------------------------------------- 1 | import "./style.scss"; 2 | 3 | /** 4 | * Fetch a random quote. 5 | * Uses the excellent, free API at: https://icanhazdadjoke.com/api 6 | * 7 | * @return {string} A single quote. 8 | */ 9 | async function fetchRandomQuote() { 10 | try { 11 | const response = await fetch("https://icanhazdadjoke.com/", { 12 | headers: { 13 | Accept: "application/json", 14 | }, 15 | }); 16 | if (response.status !== 200) { 17 | throw response; 18 | } 19 | const data = await response.json(); 20 | return data.joke; 21 | } catch (err) { 22 | console.warn("Something went wrong loading your data."); 23 | console.warn(err); 24 | } 25 | } 26 | 27 | /** 28 | * Update the current on-screen quote. 29 | */ 30 | async function updateQuote() { 31 | const quoteElement = document.querySelector(".quote"); 32 | const quoteText = await fetchRandomQuote(); 33 | 34 | // Not foolproof, but try to deal with the odd overly-long quote too. 35 | if (quoteText.length > 180) { 36 | quoteElement.classList.add("small-text"); 37 | } else { 38 | quoteElement.classList.remove("small-text"); 39 | } 40 | 41 | quoteElement.textContent = quoteText; 42 | } 43 | 44 | /** 45 | * Starts up the app. 46 | */ 47 | function start() { 48 | const refreshTime = 10000; 49 | 50 | setInterval(updateQuote, refreshTime); 51 | updateQuote(); 52 | } 53 | 54 | // Kick off your app! 55 | start(); 56 | -------------------------------------------------------------------------------- /packages/apps-editor-sdk/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { AppConfig, InitializeMessagePayload } from "./types"; 2 | 3 | // Message Types 4 | export const CONNECT = "CONNECT"; 5 | export const CONNECT_SUCCESS = "CONNECT_SUCCESS"; 6 | export const DISCONNECT = "DISCONNECT"; // Deprecated. 7 | export const INITIALIZE = "initialize"; 8 | export const INITIALIZED = "initialized"; 9 | export const START = "start"; 10 | export const STARTED = "started"; 11 | export const REQUEST_CONFIG_UPDATE = "requestConfigUpdate"; 12 | export const CONFIG_UPDATE_AVAILABLE = "configUpdateAvailable"; 13 | 14 | // Message "type"s which prefix their string with ___ 15 | export const LEGACY_PREFIXED_TYPES = [CONNECT, CONNECT_SUCCESS, DISCONNECT]; 16 | 17 | // Prepended to the start of each log message 18 | export const LOG_PREFIX = "[Apps SDK] "; 19 | 20 | // Default INITIALIZE payload for local dev and testing. 21 | export const SAMPLE_INITIALIZE_PAYLOAD: InitializeMessagePayload = { 22 | appId: "test-app-111", 23 | appInstanceId: "test-instance-222", 24 | config: { 25 | hello: "world", 26 | meaningOfLife: 42, 27 | }, 28 | context: { 29 | userInteractionEnabled: false, 30 | loggingLevel: 1, 31 | playerHeight: 1080, 32 | playerWidth: 1920, 33 | region: "eu", 34 | timezone: "Europe/London", 35 | appViewerToken: "", 36 | appManagementToken: "", 37 | }, 38 | orgId: "org-333", 39 | spaceId: "space-444", 40 | device: {}, 41 | filesByAppInstanceId: { nodes: [] }, 42 | }; 43 | -------------------------------------------------------------------------------- /examples/15five-firebase-cloud-function-example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | firebase-debug.log* 8 | firebase-debug.*.log* 9 | 10 | # Firebase cache 11 | .firebase/ 12 | 13 | # Firebase config 14 | 15 | # Uncomment this if you'd like others to create their own Firebase project. 16 | # For a team working on the same Firebase project(s), it is recommended to leave 17 | # it commented so all members can deploy to the same project(s) in .firebaserc. 18 | # .firebaserc 19 | 20 | # Runtime data 21 | pids 22 | *.pid 23 | *.seed 24 | *.pid.lock 25 | 26 | # Directory for instrumented libs generated by jscoverage/JSCover 27 | lib-cov 28 | 29 | # Coverage directory used by tools like istanbul 30 | coverage 31 | 32 | # nyc test coverage 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 36 | .grunt 37 | 38 | # Bower dependency directory (https://bower.io/) 39 | bower_components 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (http://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directories 48 | node_modules/ 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # Yarn Integrity file 63 | .yarn-integrity 64 | 65 | # dotenv environment variables file 66 | .env 67 | -------------------------------------------------------------------------------- /packages/apps-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@screencloud/apps-sdk", 3 | "version": "1.2.2", 4 | "description": "Vanilla JavaScript SDK for building ScreenCloud apps", 5 | "keywords": [ 6 | "screencloud", 7 | "apps", 8 | "javascript", 9 | "typescript" 10 | ], 11 | "author": "Michael Martin ", 12 | "homepage": "https://screencloud.github.io/developer/", 13 | "license": "ISC", 14 | "main": "lib/index.js", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/screencloud/developer.git" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/screencloud/developer/issues" 21 | }, 22 | "files": [ 23 | "lib" 24 | ], 25 | "scripts": { 26 | "build": "tsc", 27 | "start": "tsc --watch", 28 | "lint": "prettier --check --no-config 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}' && eslint 'src/**/*.{ts,tsx,js,jsx}'", 29 | "lint:fix": "prettier --write --no-config 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}' && eslint --fix 'src/**/*.{ts,tsx,js,jsx}'" 30 | }, 31 | "devDependencies": { 32 | "@typescript-eslint/eslint-plugin": "^2.29.0", 33 | "@typescript-eslint/parser": "^2.29.0", 34 | "eslint": "^6.8.0", 35 | "eslint-config-prettier": "^6.11.0", 36 | "eslint-plugin-prettier": "^3.1.3", 37 | "prettier": "^2.0.5", 38 | "typescript": "^3.8.3" 39 | }, 40 | "browserslist": "> 0.25%, not dead", 41 | "publishConfig": { 42 | "access": "public" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/content/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Develop a ScreenCloud App' 3 | metaTitle: 'Developer' 4 | metaDescription: 'Develop your own Digital Signage apps easily with ScreenCloud.' 5 | --- 6 | 7 | Welcome! So you'd like to see your own data and services on your screens? Awesome! 8 | 9 | You can build custom apps exactly like those already in the App Store. They use standard web technologies, so if you know HTML and JavaScript, you already know what to do. 10 | 11 | And apps are private to you by default. Only organizations you select, like your own, will be able to see them. Need to share those marketing stats with your company, but really want to use a chart visualization you've built yourself? Perfect, a quick custom app is probably the answer. 12 | 13 | If you later want to share your work with everyone on the App Store, that's super! Just [let us know](mailto:proservices@screencloud.io) and we'll make it happen. 14 | 15 | Head to the Overview for a quick intro to some key concepts, or go straight to Get Started. 16 | 17 | If you'd like to raise a question you can contact our [Professional Services team](mailto:proservices@screencloud.io). 18 | 19 | PS - This is still early days for our 3rd party app support. Some steps are more manual than we'd like, but we'll call them out clearly and wherever we can help, we're happy to. 20 | 21 | We'd really appreciate [your feedback](mailto:proservices@screencloud.io) on what's painful or confusing so we know where to focus our efforts next. 22 | -------------------------------------------------------------------------------- /docs/src/components/mdxComponents/index.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import { Link } from 'gatsby'; 3 | import React from 'react'; 4 | import { theme } from '../theme'; 5 | import AnchorTag from './anchor'; 6 | import CodeBlock from './codeBlock'; 7 | 8 | const StyledPre = styled('pre')` 9 | padding: 16px; 10 | background: ${theme.colors.preFormattedText}; 11 | `; 12 | 13 | export default { 14 | h1: props => ( 15 |

16 | ), 17 | h2: props => ( 18 |

19 | ), 20 | h3: props => ( 21 |

22 | ), 23 | h4: props => ( 24 |

25 | ), 26 | h5: props => ( 27 |

28 | ), 29 | h6: props => ( 30 |
31 | ), 32 | p: props =>

, 33 | pre: props => ( 34 | 35 |

36 |     
37 |   ),
38 |   code: CodeBlock,
39 |   a: AnchorTag,
40 |   Link,
41 |   // TODO add `img`
42 |   // TODO add `blockquote`
43 |   // TODO add `ul`
44 |   // TODO add `li`
45 |   // TODO add `table`
46 | };
47 | 


--------------------------------------------------------------------------------
/packages/apps-editor-sdk/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@screencloud/apps-editor-sdk",
 3 |   "version": "1.0.2",
 4 |   "description": "Vanilla JavaScript SDK for building ScreenCloud apps",
 5 |   "keywords": [
 6 |     "screencloud",
 7 |     "apps",
 8 |     "javascript",
 9 |     "typescript"
10 |   ],
11 |   "author": "Michael Martin ",
12 |   "homepage": "https://screencloud.github.io/developer/",
13 |   "license": "ISC",
14 |   "main": "lib/index.js",
15 |   "repository": {
16 |     "type": "git",
17 |     "url": "git+https://github.com/screencloud/developer.git"
18 |   },
19 |   "bugs": {
20 |     "url": "https://github.com/screencloud/developer/issues"
21 |   },
22 |   "files": [
23 |     "lib"
24 |   ],
25 |   "scripts": {
26 |     "build": "tsc",
27 |     "start": "tsc --watch",
28 |     "lint": "prettier --check --no-config 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}' && eslint 'src/**/*.{ts,tsx,js,jsx}'",
29 |     "lint:fix": "prettier --write --no-config 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}' && eslint --fix 'src/**/*.{ts,tsx,js,jsx}'"
30 |   },
31 |   "devDependencies": {
32 |     "@types/node": "^17.0.33",
33 |     "@typescript-eslint/eslint-plugin": "^2.29.0",
34 |     "@typescript-eslint/parser": "^2.29.0",
35 |     "eslint": "^6.8.0",
36 |     "eslint-config-prettier": "^6.11.0",
37 |     "eslint-plugin-prettier": "^3.1.3",
38 |     "prettier": "^2.0.5",
39 |     "typescript": "^3.8.3"
40 |   },
41 |   "browserslist": "> 0.25%, not dead",
42 |   "publishConfig": {
43 |     "access": "public"
44 |   }
45 | }
46 | 


--------------------------------------------------------------------------------
/docs/content/overview.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: 'Overview'
 3 | ---
 4 | 
 5 | An **app** lets you build experiences for screens with your own features and systems, and your own design.
 6 | 
 7 | All apps are simply webapps, or even just a single webpage. You use the same techniques you use to build any other webpage, so you can build in React, Vue, Angular, plain JavaScript, or any tool you prefer.
 8 | 
 9 | You host the app anywhere you like, and can update it any time just by pushing the updates to your own site.
10 | 
11 | In effect, we want to help you get on screen, then get back out of your way!
12 | 
13 | ## Concepts
14 | 
15 | **Studio** is the CMS where users manage all of their screens and the content on them.
16 | 
17 | An **app** is a webpage, integrated with ScreenCloud using our web SDK.
18 | 
19 | Apps run on a **Player**. The Player is the ScreenCloud product you install on your TV/FireStick/Chromebit etc. It handles things like pairing to your ScreenCloud account, scheduling, and zones.
20 | 
21 | The **App Store** is the page inside Studio that lists all of the apps available to you. This is where users will read about your app and install it.
22 | 
23 | Apps can be **Private** or **Public**. Private apps will only be available to your own organisation, or others you explicitly ask us to enable them for.
24 | 
25 | Apps take **configuration** from the user. For example, to install the _Clock_ app a user would tell us which timezone they want to display. This config data is then given to the app when it runs on the Player so it knows what to show.
26 | 
27 | All good so far? Then let's get started on your first app!
28 | 


--------------------------------------------------------------------------------
/examples/15Five-firebase-webapp-example/src/components/slide-show/Slide.js:
--------------------------------------------------------------------------------
 1 | import React, { memo } from 'react';
 2 | import './slide-show.scss';
 3 | 
 4 | /**
 5 |  * Slide Component - here is where you create the view for the data you fetched from server. Each slide will  be shown on
 6 |  *                   on screen for the length of time you set in the AppContainer.js
 7 |  */
 8 | 
 9 | var MONTHS =["Jan","Feb","Mar","April","May","June","July","Aug","Sept","Oct","Nov","Dec"];
10 | 
11 | export const Slide = (props) => {
12 |     const {text, creationTimestamp, creatorFullName, receiverFullName} = props.data;
13 |     return (
14 |         
15 |
16 |
17 |
18 | {receiverFullName} has gotten a High Five ✋ 19 |
20 |
21 | {creationTimestamp.getDate()} {MONTHS[creationTimestamp.getMonth()]} 22 |
23 |
24 |
25 |
{creatorFullName}:
26 |
"{receiverFullName} {text}"
27 |
28 |
29 | 30 |
31 |
32 |
33 | ); 34 | }; 35 | 36 | export default memo(Slide); -------------------------------------------------------------------------------- /docs/src/components/sidebar/treeNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import config from '../../../config'; 3 | import ClosedSvg from '../../images/closed'; 4 | import OpenedSvg from '../../images/opened'; 5 | import Link from '../link'; 6 | 7 | const TreeNode = ({ className = '', setCollapsed, collapsed, url, title, items, ...rest }) => { 8 | const isCollapsed = collapsed[url]; 9 | 10 | const collapse = () => { 11 | setCollapsed(url); 12 | }; 13 | 14 | const hasChildren = items.length !== 0; 15 | 16 | let location; 17 | 18 | if (typeof document != 'undefined') { 19 | location = document.location; 20 | } 21 | const active = 22 | location && (location.pathname === url || location.pathname === config.gatsby.pathPrefix + url); 23 | 24 | const calculatedClassName = `${className} item ${active ? 'active' : ''}`; 25 | 26 | return ( 27 |
  • 28 | {title && ( 29 | 30 | {title} 31 | {!config.sidebar.frontLine && title && hasChildren ? ( 32 | 35 | ) : null} 36 | 37 | )} 38 | 39 | {!isCollapsed && hasChildren ? ( 40 |
      41 | {items.map((item, index) => ( 42 | 48 | ))} 49 |
    50 | ) : null} 51 |
  • 52 | ); 53 | }; 54 | 55 | export default TreeNode; 56 | -------------------------------------------------------------------------------- /packages/apps-sdk/src/messages.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CONNECT, 3 | CONNECT_SUCCESS, 4 | INITIALIZED, 5 | START, 6 | STARTED, 7 | } from "./constants"; 8 | import { InitializeMessagePayload } from "./types"; 9 | 10 | /** 11 | * Messages created by the App, and sent to the Player. 12 | */ 13 | export type AppMessage = ConnectMessage | InitializedMessage | StartedMessage; 14 | 15 | /** 16 | * Messages created by the Player, and send to the app. 17 | */ 18 | export type PlayerMessage = 19 | | ConnectSuccessMessage 20 | | InitializeMessage 21 | | StartMessage; 22 | 23 | export interface ConnectMessage { 24 | type: typeof CONNECT; 25 | } 26 | 27 | export const connectMessage = (): ConnectMessage => { 28 | return { 29 | type: CONNECT, 30 | }; 31 | }; 32 | 33 | export interface InitializedMessage { 34 | type: typeof INITIALIZED; 35 | } 36 | 37 | export const initializedMessage = (): InitializedMessage => { 38 | return { 39 | type: INITIALIZED, 40 | }; 41 | }; 42 | 43 | export interface StartedMessage { 44 | type: typeof STARTED; 45 | } 46 | 47 | export const startedMessage = (): StartedMessage => { 48 | return { 49 | type: STARTED, 50 | }; 51 | }; 52 | 53 | /** 54 | * Messages the Parent can send 55 | */ 56 | export interface ConnectSuccessMessage { 57 | type: typeof CONNECT_SUCCESS; 58 | } 59 | 60 | export interface InitializeMessage { 61 | type: "initialize"; 62 | payload: InitializeMessagePayload; 63 | } 64 | 65 | export const initializeMessage = ( 66 | payload: InitializeMessagePayload 67 | ): InitializeMessage => { 68 | return { 69 | type: "initialize", 70 | payload, 71 | }; 72 | }; 73 | 74 | export interface StartMessage { 75 | type: typeof START; 76 | } 77 | -------------------------------------------------------------------------------- /docs/content/preloading.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Preloading' 3 | --- 4 | 5 | Preloading makes your app feel snappy and fast on screen. 6 | 7 | It lets the Player load your app slightly before it is visible on screen, so you have time to fetch any data or media you need in advance. 8 | 9 | Then when the Player makes your App visible, it lets you know that it's time to kick-off. 10 | 11 | This way you can make the API calls and fetch assets, but users don't miss the "start" of your content. It can all sit waiting, and snap into action the second the app is visible. 12 | 13 | ## How to Use 14 | 15 | Carrying on from the Get Started guide, our code looked like this: 16 | 17 | ```javascript 18 | const sc = await connectScreenCloud(testData); 19 | const refreshTime = sc.getConfig().refreshTimeSeconds * 1000; 20 | 21 | setInterval(updateQuote, refreshTime); 22 | updateQuote(); 23 | ``` 24 | 25 | This means we connect to ScreenCloud, then immediately start out `updateQuote` interval. If the Player preloads our app 20 seconds in advance, our users will miss the first few quotes. 26 | 27 | The `sc` object exposes a handy Promise for this. `sc.onAppStarted()` will resolve when your app is visible on screen, so we just move our `setInterval` call to wait for it. 28 | 29 | ```javascript 30 | const sc = await connectScreenCloud(testData); 31 | const refreshTime = sc.getConfig().refreshTimeSeconds * 1000; 32 | 33 | // Fetch our initial data immediately. 34 | updateQuote(); 35 | 36 | /** 37 | * When app is started (i.e. visible on screen), start the timer to refresh quotes periodically. 38 | */ 39 | sc.onAppStarted().then(() => { 40 | setInterval(updateQuote, refreshTime); 41 | }); 42 | ``` 43 | 44 | Done! Now we fetch the first quote in advance so that we're ready the second the user is, but we only jump to the 2nd quote when we know users have had a chance to see the first. 45 | -------------------------------------------------------------------------------- /examples/react-firebase-example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
    32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/javascript-app/src/index.js: -------------------------------------------------------------------------------- 1 | import { connectScreenCloud } from "@screencloud/apps-sdk"; 2 | import "./style.css"; 3 | 4 | /** 5 | * Fetch a random quote. 6 | * Uses the excellent, free API at: https://icanhazdadjoke.com/api 7 | * 8 | * @return {string} A single quote. 9 | */ 10 | async function fetchRandomQuote() { 11 | try { 12 | const response = await fetch("https://icanhazdadjoke.com/", { 13 | headers: { 14 | Accept: "application/json", 15 | }, 16 | }); 17 | if (response.status !== 200) { 18 | throw response; 19 | } 20 | const data = await response.json(); 21 | return data.joke; 22 | } catch (err) { 23 | console.warn("Something went wrong loading your data."); 24 | console.warn(err); 25 | } 26 | } 27 | 28 | /** 29 | * Update the current on-screen quote. 30 | */ 31 | async function updateQuote() { 32 | const quoteElement = document.querySelector(".quote"); 33 | const quoteText = await fetchRandomQuote(); 34 | 35 | // Not foolproof, but try to deal with the odd overly-long quote too. 36 | if (quoteText.length > 180) { 37 | quoteElement.classList.add("small-text"); 38 | } else { 39 | quoteElement.classList.remove("small-text"); 40 | } 41 | 42 | quoteElement.textContent = quoteText; 43 | } 44 | 45 | /** 46 | * Starts up the app. 47 | */ 48 | async function start() { 49 | let testData; 50 | 51 | if (process.env.NODE_ENV === "development") { 52 | testData = { 53 | config: { 54 | refreshTimeSeconds: 10, 55 | }, 56 | }; 57 | } 58 | 59 | const sc = await connectScreenCloud(testData); 60 | const refreshTime = sc.getConfig().refreshTimeSeconds * 1000; 61 | 62 | // Fetch our initial data immediately. 63 | updateQuote(); 64 | 65 | /** 66 | * When app is started (i.e. visible on screen), start the timer to refresh quotes periodically. 67 | */ 68 | sc.onAppStarted().then(() => { 69 | setInterval(updateQuote, refreshTime); 70 | }); 71 | } 72 | 73 | // Kick off your app! 74 | start(); 75 | -------------------------------------------------------------------------------- /docs/src/components/styles/Docs.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import { theme } from '../theme'; 3 | 4 | export const StyledHeading = styled('h1')` 5 | font-size: 32px; 6 | line-height: 1.5; 7 | font-weight: 500; 8 | border-left: 6px solid ${theme.colors.scYellowLight}; 9 | padding: 0 16px; 10 | flex: 1; 11 | margin-top: 0; 12 | padding-top: 0; 13 | color: ${theme.colors.heading}; 14 | `; 15 | 16 | export const Edit = styled('div')` 17 | padding: 1rem 1.5rem; 18 | text-align: right; 19 | 20 | a { 21 | font-size: 14px; 22 | font-weight: 500; 23 | line-height: 1em; 24 | text-decoration: none; 25 | color: #555; 26 | border: 1px solid rgb(211, 220, 228); 27 | cursor: pointer; 28 | border-radius: 3px; 29 | transition: all 0.2s ease-out 0s; 30 | text-decoration: none; 31 | color: rgb(36, 42, 49); 32 | background-color: rgb(255, 255, 255); 33 | box-shadow: rgba(116, 129, 141, 0.1) 0px 1px 1px 0px; 34 | height: 30px; 35 | padding: 5px 16px; 36 | &:hover { 37 | background-color: rgb(245, 247, 249); 38 | } 39 | } 40 | `; 41 | 42 | export const StyledMainWrapper = styled.div` 43 | max-width: 750px; 44 | color: ${theme.colors.text}; 45 | 46 | ul, 47 | ol { 48 | -webkit-padding-start: 40px; 49 | -moz-padding-start: 40px; 50 | -o-padding-start: 40px; 51 | margin: 24px 0px; 52 | padding: 0px 0px 0px 2em; 53 | 54 | li { 55 | font-size: 16px; 56 | line-height: 1.8; 57 | font-weight: 400; 58 | } 59 | } 60 | 61 | a:link { 62 | transition: border-color 0.1s ease-in; 63 | color: ${theme.colors.text}; 64 | border-bottom: 1px solid ${theme.colors.text}; 65 | } 66 | 67 | a:visited { 68 | color: ${theme.colors.scGrey}; 69 | } 70 | 71 | a:hover, 72 | a:active { 73 | border-color: #fff; 74 | } 75 | 76 | code { 77 | border: 1px solid #ede7f3; 78 | border-radius: 4px; 79 | padding: 2px 6px; 80 | font-size: 0.9375em; 81 | 82 | background: ${theme.colors.background}; 83 | } 84 | 85 | @media (max-width: 767px) { 86 | padding: 0 15px; 87 | } 88 | `; 89 | -------------------------------------------------------------------------------- /packages/apps-sdk/src/utils/postMessage.ts: -------------------------------------------------------------------------------- 1 | import { LEGACY_PREFIXED_TYPES, LOG_PREFIX } from "../constants"; 2 | import { AppMessage, PlayerMessage } from "../messages"; 3 | 4 | // TODO - postMessage natively serializes elements. Why do we JSON.stringify everything? 5 | // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm 6 | 7 | /** 8 | * Send a postMessage to the player. 9 | */ 10 | export const sendMessage = ( 11 | message: AppMessage, 12 | targetOrigin: string 13 | ): void => { 14 | const parent = window.parent || window.opener; 15 | 16 | if (!parent) { 17 | console.log(LOG_PREFIX + "Could not send message.", message); 18 | return; 19 | } 20 | 21 | const { type } = message; 22 | 23 | // Backwards compatibility: 24 | // CONNECT, CONNECT_SUCCESS, DISCONNECT messages add a ___ prefix. 25 | // The rest nest their data under a 2nd "data" key. 26 | let processedMessage; 27 | 28 | if (LEGACY_PREFIXED_TYPES.includes(type)) { 29 | processedMessage = `___${JSON.stringify(message)}`; 30 | } else { 31 | processedMessage = JSON.stringify({ 32 | data: message, 33 | }); 34 | } 35 | 36 | if (process.env.NODE_ENV === "development") { 37 | console.log(LOG_PREFIX + "Sending message", message); 38 | } 39 | parent.postMessage(processedMessage, targetOrigin); 40 | }; 41 | 42 | /** 43 | * Parse the string received from a parent into a typed Message. 44 | */ 45 | export const parseMessage = (event: MessageEvent): PlayerMessage => { 46 | const { origin, data } = event; 47 | if (origin === window.location.origin) { 48 | throw `Ignoring messages sent by the same origin (e.g. devtools): ${origin}`; 49 | } 50 | 51 | // Only CONNECT, CONNECT_SUCCESS, DISCONNECT messages add this ___ thing. 52 | // The rest nest their data under a 2nd "data" key. 53 | // TODO - Remove this complexity. 54 | try { 55 | const parsed = 56 | data.substr(0, 3) === "___" 57 | ? JSON.parse(data.substring(3)) 58 | : JSON.parse(data).data; 59 | 60 | return parsed as PlayerMessage; 61 | } catch (e) { 62 | throw e; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /examples/15five-firebase-cloud-function-example/functions/index.js: -------------------------------------------------------------------------------- 1 | const functions = require('firebase-functions'); 2 | const superagent = require('superagent'); 3 | 4 | // API ACCESS TOKEN is stored in firebase config store for security reasons as you would'nt want this visible to public 5 | const TOKEN = functions.config().five.token; 6 | const BASE_URL = 'https://my.15five.com/api/public'; 7 | const HIGH_FIVE_URL = `${BASE_URL}/high-five/?created_on_start=`; 8 | 9 | const getDateMonthAgo = () => { 10 | const d = new Date(); 11 | 12 | d.setMonth(d.getMonth() - 1); 13 | 14 | const month = d.getMonth() < 10 ? '0' + d.getMonth() : d.getMonth(); 15 | const date = d.getDate() < 10 ? '0' + d.getDate() : d.getDate(); 16 | 17 | return `${d.getFullYear()}-${month}-${date} 00:00:00` 18 | } 19 | 20 | const createResponseObject = ({id, text, create_ts, creator_details, receivers}) => { 21 | return { 22 | id, 23 | text, 24 | creationTimestamp: create_ts, 25 | creatorFullName: creator_details.full_name, 26 | receiversList: receivers ? receivers.map(r => { 27 | return { 28 | fullName: r.full_name 29 | } 30 | }) : [], 31 | }; 32 | }; 33 | 34 | const responseMapper = (responseData) => { 35 | return responseData.results.reduce((accumulator, currentValue) => { 36 | if (currentValue.creator_details && currentValue.creator_details.full_name.toLowerCase() !== "15five") { 37 | accumulator.push(createResponseObject(currentValue)); 38 | } 39 | return accumulator; 40 | }, []); 41 | } 42 | 43 | exports.highFives = functions.https.onRequest(async (request, response) => { 44 | response.set('Access-Control-Allow-Origin', '*'); 45 | console.log(getDateMonthAgo()); 46 | try { 47 | const res = await superagent.get(HIGH_FIVE_URL + getDateMonthAgo()).set('Authorization', `Bearer ${TOKEN}`); 48 | 49 | console.log(res.body) 50 | return response.status(200).send({data: responseMapper(res.body)}); 51 | } catch(error) { 52 | return response.status(500).send('Sorry there was an issue fetching power ups') 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /examples/javascript-app/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 4 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 5 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 6 | 7 | module.exports = { 8 | entry: "./src/index", 9 | output: { 10 | path: path.resolve(__dirname, "./dist"), 11 | filename: "[name].[chunkhash].js", 12 | }, 13 | 14 | module: { 15 | rules: [ 16 | { 17 | test: [/.js$|.ts$/], 18 | exclude: /(node_modules)/, 19 | use: { 20 | loader: "babel-loader", 21 | options: { 22 | presets: ["@babel/preset-env", "@babel/typescript"], 23 | }, 24 | }, 25 | }, 26 | { 27 | test: [/.css$|.scss$/], 28 | use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], 29 | }, 30 | { 31 | test: /\.(png|jpg|jpeg|gif|svg)$/, 32 | use: [ 33 | { 34 | loader: "file-loader", 35 | options: { 36 | name: "[name].[ext]", 37 | outputPath: "images/", 38 | }, 39 | }, 40 | ], 41 | }, 42 | ], 43 | }, 44 | 45 | resolve: { 46 | alias: { 47 | "@scss": path.resolve(__dirname, "../src/styles/scss"), 48 | "@img": path.resolve(__dirname, "../src/images"), 49 | "@": path.resolve(__dirname, "../src"), 50 | }, 51 | modules: ["node_modules", path.resolve(__dirname, "src")], 52 | extensions: [".js", ".ts"], 53 | }, 54 | 55 | plugins: [ 56 | new HtmlWebpackPlugin({ 57 | template: "./src/index.html", 58 | inject: true, 59 | minify: { 60 | removeComments: true, 61 | collapseWhitespace: true, 62 | }, 63 | }), 64 | new MiniCssExtractPlugin({ 65 | filename: "style.[chunkhash].css", 66 | }), 67 | new CopyWebpackPlugin([ 68 | { 69 | from: "./src/images", 70 | to: "images", 71 | }, 72 | ]), 73 | new CleanWebpackPlugin(), 74 | ], 75 | 76 | devServer: { 77 | clientLogLevel: "silent", 78 | port: 8000, 79 | }, 80 | }; 81 | -------------------------------------------------------------------------------- /examples/typescript-app/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 4 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 5 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 6 | 7 | module.exports = { 8 | entry: "./src/index", 9 | output: { 10 | path: path.resolve(__dirname, "./dist"), 11 | filename: "[name].[chunkhash].js", 12 | }, 13 | 14 | module: { 15 | rules: [ 16 | { 17 | test: [/.js$|.ts$/], 18 | exclude: /(node_modules)/, 19 | use: { 20 | loader: "babel-loader", 21 | options: { 22 | presets: ["@babel/preset-env", "@babel/typescript"], 23 | }, 24 | }, 25 | }, 26 | { 27 | test: [/.css$|.scss$/], 28 | use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], 29 | }, 30 | { 31 | test: /\.(png|jpg|jpeg|gif|svg)$/, 32 | use: [ 33 | { 34 | loader: "file-loader", 35 | options: { 36 | name: "[name].[ext]", 37 | outputPath: "images/", 38 | }, 39 | }, 40 | ], 41 | }, 42 | ], 43 | }, 44 | 45 | resolve: { 46 | alias: { 47 | "@scss": path.resolve(__dirname, "../src/styles/scss"), 48 | "@img": path.resolve(__dirname, "../src/images"), 49 | "@": path.resolve(__dirname, "../src"), 50 | }, 51 | modules: ["node_modules", path.resolve(__dirname, "src")], 52 | extensions: [".js", ".ts"], 53 | }, 54 | 55 | plugins: [ 56 | new HtmlWebpackPlugin({ 57 | template: "./src/index.html", 58 | inject: true, 59 | minify: { 60 | removeComments: true, 61 | collapseWhitespace: true, 62 | }, 63 | }), 64 | new MiniCssExtractPlugin({ 65 | filename: "style.[chunkhash].css", 66 | }), 67 | new CopyWebpackPlugin([ 68 | { 69 | from: "./src/images", 70 | to: "images", 71 | }, 72 | ]), 73 | new CleanWebpackPlugin(), 74 | ], 75 | 76 | devServer: { 77 | clientLogLevel: "silent", 78 | port: 8000, 79 | }, 80 | }; 81 | -------------------------------------------------------------------------------- /docs/src/html.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import config from '../config'; 4 | 5 | export default class HTML extends React.Component { 6 | render() { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | {config.siteMetadata.ogImage ? ( 14 | 15 | ) : null} 16 | 17 | {config.siteMetadata.ogImage ? ( 18 | 19 | ) : null} 20 | {config.siteMetadata.favicon ? ( 21 | 22 | ) : null} 23 | 24 | {this.props.headComponents} 25 | 26 | 27 | {this.props.preBodyComponents} 28 |
    29 | {this.props.postBodyComponents} 30 |