-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(playground): ability to open examples in Stackblitz (#2215)
- Loading branch information
1 parent
f6fb9f1
commit 42bf073
Showing
21 changed files
with
14,631 additions
and
296 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export enum UsageTarget { | ||
Html = 'Basic', | ||
Angular = 'Angular', | ||
React = 'React', | ||
Vue = 'Vue', | ||
} | ||
|
||
export const UsageTargetList = Object.keys(UsageTarget); | ||
|
||
export enum Mode { | ||
iOS = 'ios', | ||
MD = 'md', | ||
} | ||
|
||
export type SupportedFrameworks = 'angular' | 'react' | 'vue' | 'javascript'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import sdk from '@stackblitz/sdk'; | ||
|
||
// The default title to use for Stackblitz examples (when not overwritten) | ||
const DEFAULT_EDITOR_TITLE = 'Ionic Docs Example'; | ||
// The default description to use for Stackblitz examples (when not overwritten) | ||
const DEFAULT_EDITOR_DESCRIPTION = ''; | ||
// Default package version to use for all @ionic/* packages. | ||
const DEFAULT_IONIC_VERSION = '^6.0.0'; | ||
|
||
export interface EditorOptions { | ||
/** | ||
* The title of the Stackblitz example. | ||
*/ | ||
title?: string; | ||
/** | ||
* The description of the Stackblitz example. | ||
*/ | ||
description?: string; | ||
} | ||
|
||
const loadSourceFiles = async (files: string[]) => { | ||
const sourceFiles = await Promise.all(files.map(f => fetch(`/docs/code/stackblitz/${f}`))); | ||
return (await Promise.all(sourceFiles.map(res => res.text()))); | ||
} | ||
|
||
const openHtmlEditor = async (code: string, options?: EditorOptions) => { | ||
const [index_ts, index_html] = await loadSourceFiles([ | ||
'html/index.ts', | ||
'html/index.html', | ||
]); | ||
|
||
sdk.openProject({ | ||
template: 'typescript', | ||
title: options?.title ?? DEFAULT_EDITOR_TITLE, | ||
description: options?.description ?? DEFAULT_EDITOR_DESCRIPTION, | ||
files: { | ||
// Injects our code sample into the body of the HTML document | ||
'index.html': index_html.replace(/<body><\/body>/g, `<body>\n` + code + '</body>'), | ||
'index.ts': index_ts, | ||
}, | ||
dependencies: { | ||
'@ionic/core': DEFAULT_IONIC_VERSION, | ||
}, | ||
}) | ||
} | ||
|
||
const openAngularEditor = async (code: string, options?: EditorOptions) => { | ||
const [main_ts, app_module_ts, app_component_ts, styles_css, angular_json] = await loadSourceFiles([ | ||
'angular/main.ts', | ||
'angular/app.module.ts', | ||
'angular/app.component.ts', | ||
'angular/styles.css', | ||
'angular/angular.json' | ||
]) | ||
|
||
sdk.openProject({ | ||
template: 'angular-cli', | ||
title: options?.title ?? DEFAULT_EDITOR_TITLE, | ||
description: options?.description ?? DEFAULT_EDITOR_DESCRIPTION, | ||
files: { | ||
'src/main.ts': main_ts, | ||
'src/polyfills.ts': `import 'zone.js/dist/zone';`, | ||
'src/app/app.module.ts': app_module_ts, | ||
'src/app/app.component.ts': app_component_ts, | ||
'src/app/app.component.html': code, | ||
'src/index.html': '<app-root></app-root>', | ||
'src/styles.css': styles_css, | ||
'angular.json': angular_json, | ||
}, | ||
dependencies: { | ||
'@ionic/angular': DEFAULT_IONIC_VERSION, | ||
}, | ||
}); | ||
} | ||
|
||
const openReactEditor = async (code: string, options?: EditorOptions) => { | ||
// Matches the name after `export default` to use as the component tag. | ||
let componentTagName; | ||
try { | ||
componentTagName = new RegExp(/function([\S\s]*?)\(/g).exec(code)[1].trim(); | ||
} catch (e) { | ||
console.error('Error parsing the component tag name from the React code snippet. Please make sure that the code snippet for React ends with export default ComponentName;'); | ||
} | ||
|
||
if (!componentTagName) { | ||
return; | ||
} | ||
|
||
const [index_js, app_tsx] = await loadSourceFiles([ | ||
'react/index.js', | ||
'react/app.tsx' | ||
]); | ||
|
||
const app_tsx_renamed = app_tsx | ||
// Inserts the component name from the sample into the <IonApp> tag. | ||
.replace(/<IonApp><\/IonApp>/g, `<IonApp><${componentTagName} /></IonApp>`) | ||
// Imports the component from our `main` example file. | ||
.replace(/setupIonicReact\(\);/g, `import ${componentTagName} from "./main";\n\n` + 'setupIonicReact();'); | ||
|
||
sdk.openProject({ | ||
template: 'create-react-app', | ||
title: options?.title ?? DEFAULT_EDITOR_TITLE, | ||
description: options?.description ?? DEFAULT_EDITOR_DESCRIPTION, | ||
files: { | ||
'index.html': `<div id="root"></div>`, | ||
'index.js': index_js, | ||
'App.js': app_tsx_renamed, | ||
'main.js': code, | ||
}, | ||
dependencies: { | ||
react: 'latest', | ||
'react-dom': 'latest', | ||
'@ionic/react': DEFAULT_IONIC_VERSION, | ||
// Stackblitz requires this dependency to run | ||
'@stencil/core': '^2.13.0', | ||
}, | ||
}) | ||
} | ||
|
||
const openVueEditor = async (code: string, options?: EditorOptions) => { | ||
const [package_json, index_html, vite_config_js, main_js, app_vue] = await loadSourceFiles([ | ||
'vue/package.json', | ||
'vue/index.html', | ||
'vue/vite.config.js', | ||
'vue/main.js', | ||
'vue/App.vue' | ||
]); | ||
/** | ||
* We have to use Stackblitz web containers here (node template), due | ||
* to multiple issues with Vite, Vue/Vue Router and Vue 3's script setup. | ||
* | ||
* https://github.com/stackblitz/core/issues/1308 | ||
*/ | ||
sdk.openProject({ | ||
template: 'node', | ||
title: options?.title ?? DEFAULT_EDITOR_TITLE, | ||
description: options?.description ?? DEFAULT_EDITOR_DESCRIPTION, | ||
files: { | ||
'src/App.vue': app_vue, | ||
'src/components/Example.vue': code, | ||
'src/main.js': main_js, | ||
'index.html': index_html, | ||
'vite.config.js': vite_config_js, | ||
'package.json': package_json, | ||
'.stackblitzrc': `{ | ||
"startCommand": "yarn run dev" | ||
}` | ||
} | ||
}); | ||
} | ||
|
||
export { openAngularEditor, openHtmlEditor, openReactEditor, openVueEditor }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Stackblitz | ||
|
||
This directory contains the source files for generating the individual framework targets for a playground examples. The contents of the files will be loaded and injected into the Stackblitz example that is opened from the Playground. | ||
|
||
## Angular | ||
|
||
| File | Description | | ||
| ------------------ | ------------------------------------------------------ | | ||
| `angular.json` | Main configuration file for any Angular application. | | ||
| `app.component.ts` | Primary component class/entry point. | | ||
| `app.module.ts` | Primary `AppModule`. Specifies required `IonicModule`. | | ||
| `main.ts` | Responsive for bootstrapping the main `AppModule`. | | ||
| `styles.css` | Ionic default styles | | ||
|
||
## HTML | ||
|
||
| File | Description | | ||
| ------------ | ----------------------------------------------------------------- | | ||
| `index.html` | Main template file with CDN link to latest `@ionic/core` release. | | ||
| `index.ts` | Defines the Stencil hydrated bundle for Ionic. | | ||
|
||
## React | ||
|
||
| File | Description | | ||
| ---------- | -------------------------------------------------------------------------------------------- | | ||
| `app.tsx` | Imports required Ionic styles and `setupIonicReact()` function to initialize web components. | | ||
| `index.js` | Boilerplate to render a React app. | | ||
|
||
## Vue | ||
|
||
| File | Description | | ||
| ---------------- | ------------------------------------------------------------- | | ||
| `App.vue` | Main Vue component that wraps each example in `ion-app`. | | ||
| `index.html` | The HTML template to create an element to mount Vue to. | | ||
| `main.js` | Initializes Ionic Vue and imports global styles. | | ||
| `package.json` | Project specific dependencies to create an example with Vite. | | ||
| `vite.config.js` | Vite configuration file. | |
Oops, something went wrong.