Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(playground): add support for generating a new playground #2994

Merged
merged 28 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e14eb22
Add prompts and generate vue file
mapsandapps Jun 9, 2023
61e5dc3
Generate other files
mapsandapps Jun 9, 2023
62003d8
Merge branch 'main' into playground-hygen
mapsandapps Jun 9, 2023
af3ab6b
Use variables in headers
mapsandapps Jun 9, 2023
e648bc5
Add readme
mapsandapps Jun 9, 2023
9fe4970
Add prompt with option to generate css files
mapsandapps Jun 9, 2023
7f892c4
Add version to prompt and modify files accordingly
mapsandapps Jun 9, 2023
e550592
Simplify syntax
mapsandapps Jun 9, 2023
bce58e7
Update readme
mapsandapps Jun 9, 2023
0c56e30
Refactor
mapsandapps Jun 9, 2023
94e0d5d
Remove unnecessary code
mapsandapps Jun 9, 2023
be0ce65
Update comments
mapsandapps Jun 9, 2023
b886304
Adjust index and demo for css vs no css
mapsandapps Jun 9, 2023
a322b38
Clarify comments
mapsandapps Jun 9, 2023
9905e53
Fix relative paths
mapsandapps Jun 9, 2023
be300d2
A couple fixes for css
mapsandapps Jun 9, 2023
e02db6e
Apply suggestions from code review
mapsandapps Jun 26, 2023
9aa8d83
Address PR review
mapsandapps Jun 26, 2023
5c37cb7
Address PR review
mapsandapps Jun 26, 2023
7bb71b3
Add hint for component name casing
mapsandapps Jun 27, 2023
f04be20
Add Angular TS option
mapsandapps Jun 27, 2023
705002b
Reformat to use advanced prompting
mapsandapps Jun 28, 2023
8e9df52
Refactor where markdown output comes from
mapsandapps Jun 28, 2023
e96c425
Remove stuff I forgot to remove
mapsandapps Jun 28, 2023
ffc5df3
Remove default value for path; add validation
mapsandapps Jun 28, 2023
4c041cb
Update copy
mapsandapps Jun 28, 2023
eaf5fd1
Improve validation of path
mapsandapps Jun 28, 2023
ecc4d1a
Add validation for component name
mapsandapps Jun 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Ionic's documentation is built using [Docusaurus](https://docusaurus.io/). The c
- `components/` - styles split out into the components they target
- `static/`
- `demos/` - self-contained demos, optionally presented by pages via `demoUrl` YAML frontmatter
- `usage/` - playgrounds that can be scaffolded by running `npm run playground:new` [(docs)](_templates/README.md#new-playground-template)
averyjohnston marked this conversation as resolved.
Show resolved Hide resolved
- `versioned_docs/` - versions of the docs created by the docusaurus versioning command
- `versioned_sidebars/` - versions of the docs sidebars created by the docusaurus versioning command

Expand Down
32 changes: 32 additions & 0 deletions _templates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Hygen templates

The templates in this directory are intended to be used with [hygen](https://www.hygen.io/) to generate boilerplate files. Check out [the root package.json](../package.json) to see if there are any custom commands to use them (e.g. `npm run playground:new`). You can also run e.g. `hygen playground new` to use a generator.

Some helpful docs links for updating/creating templates:

- [enquirer](https://github.com/enquirer/enquirer#toggle-prompt) for building command line prompts
- [inflection](https://www.hygen.io/docs/templates#helpers-and-inflections) and [change case](https://www.hygen.io/docs/templates#change-case-helpers) for e.g. changing the case of variables submitted via the prompts

# New playground template

## Generation

To create a new playground, run `npm run playground:new`. This will walk you through some prompts to decide what files for the generator to scaffold for the playground, and what their paths should be.

The path defaults to `basic`. If there is already a basic playground, you'll want to input a different path for the playground.

The CSS option will add extra files if you need to include custom CSS in your playground. This is often not needed.
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved

If you need a component for multiple versions of Ionic Framework, you (currently) need to run the generator once for each version.

## Usage

Once you've generated your playground, you need to add it to the main markdown file in the docs (e.g. [docs/api/button.md](../docs/api/button.md)) by doing something similar to the following example:

```
## Feature

import Feature from '@site/static/usage/v7/button/feature/index.md';

<Feature />
Comment on lines +27 to +31
Copy link
Contributor

@averyjohnston averyjohnston Jun 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally optional, but it might be cool if the command could spit out this code for you to copy-paste, dynamically using the (formatted) name of the innermost directory created as the feature name. Don't worry about it if it would be a big lift, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea!! There's probably a more elegant way we could do it, but I added an MVP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this with a little improvement, although it still would be better if it only gets logged if the files are successfully generated. (But at least now the copy doesn't state that the generation succeeded.)

```
7 changes: 7 additions & 0 deletions _templates/playground/new/angular.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# this file's location depends on whether or not the css option is selected via the prompt
to: "<%= `static/usage/v${version}/${name.replace('ion-', '')}/${path}/${css ? 'angular/example_component_html.md' : 'angular.md'}` %>"
---
```html
<<%= name %>></<%= name %>>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# this file only gets generated if `css` (from the command line prompt) is true
to: "<%= css ? `static/usage/v${version}/${name.replace('ion-', '')}/${path}/angular/example_component_css.md` : null %>"
---
```css
<%= name %> {
/* styles go here */
}
```
32 changes: 32 additions & 0 deletions _templates/playground/new/demo.html.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
arbitrary: <% nameWithoutIon = name.replace('ion-', ''); numberOfAncestors = (path.match(/\//g) || []).length; directoryChanges = '../'.repeat(numberOfAncestors) %>
to: "<%= `static/usage/v${version}/${nameWithoutIon}/${path}/demo.html` %>"
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= h.changeCase.titleCase(nameWithoutIon) %></title>
<link rel="stylesheet" href="<%= directoryChanges %>../../../common.css" />
<script src="<%= directoryChanges %>../../../common.js"></script>
Comment on lines +11 to +12
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps there's a way to do this without using relative paths? I couldn't quickly find one.

<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@<%= version %>/dist/ionic/ionic.esm.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@<%= version %>/css/ionic.bundle.css" /><% if (css){ %>

<style>
<%= name %> {
/* styles go here */
}
</style><% } %>
</head>

<body>
<ion-app>
<ion-content>
<div class="container">
<<%= name %>></<%= name %>>
</div>
</ion-content>
</ion-app>
</body>
</html>
13 changes: 13 additions & 0 deletions _templates/playground/new/index.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
arbitrary: <% nameWithoutIon = name.replace('ion-', '') %>
# this template is only used if `css` (from the command line prompt) is false
to: "<%= css ? null : `static/usage/v${version}/${nameWithoutIon}/${path}/index.md` %>"
---
import Playground from '@site/src/components/global/Playground';

import javascript from './javascript.md';
import react from './react.md';
import vue from './vue.md';
import angular from './angular.md';

<Playground version="<%= version %>" code={{ javascript, react, vue, angular }} src="<%= `usage/v${version}/${nameWithoutIon}/${path}/demo.html` %>" />
37 changes: 37 additions & 0 deletions _templates/playground/new/index_with_css.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
arbitrary: <% nameWithoutIon = name.replace('ion-', '') %>
# this template is only used if `css` (from the command line prompt) is true
to: "<%= css ? `static/usage/v${version}/${nameWithoutIon}/${path}/index.md` : null %>"
---
import Playground from '@site/src/components/global/Playground';

import javascript from './javascript.md';

import react_main_tsx from './react/main_tsx.md';
import react_main_css from './react/main_css.md';

import vue from './vue.md';

import angular_example_component_html from './angular/example_component_html.md';
import angular_example_component_css from './angular/example_component_css.md';

<Playground
version="<%= version %>"
code={{
javascript,
react: {
files: {
'src/main.tsx': react_main_tsx,
'src/main.css': react_main_css,
},
},
vue,
angular: {
files: {
'src/app/example.component.html': angular_example_component_html,
'src/app/example.component.css': angular_example_component_css,
},
},
}}
src="<%= `usage/v${version}/${nameWithoutIon}/${path}/demo.html` %>"
/>
12 changes: 12 additions & 0 deletions _templates/playground/new/javascript.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
to: "<%= `static/usage/v${version}/${name.replace('ion-', '')}/${path}/javascript.md` %>"
---
```html
<<%= name %>></<%= name %>><% if (css){ %>

<style>
<%= name %> {
/* styles go here */
}
</style><% } %>
```
32 changes: 32 additions & 0 deletions _templates/playground/new/prompt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// see types of prompts:
// https://github.com/enquirer/enquirer/tree/master/examples
//
module.exports = [
{
type: 'input',
name: 'name',
message: 'Which component is this playground for?',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very open to copy changes for the prompts in this file. I just put the first thing that came to mind.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a note that the component name must be kebab case? For example writing "IonButton" won't work as expected

initial: 'ion-button',
},
{
type: 'input',
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved
name: 'path',
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved
message: 'What should the playground path be?',
hint: 'e.g. `theming/colors`',
initial: 'basic',
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved
},
{
type: 'select',
name: 'version',
message: 'Select the Ionic Framework version for the playground',
initial: '7',
choices: ['6', '7'],
},
{
type: 'toggle',
name: 'css',
message: 'Do you want CSS scaffolded?',
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved
enabled: 'Yes',
disabled: 'No',
},
];
17 changes: 17 additions & 0 deletions _templates/playground/new/react.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
arbitrary: <% pascalName = h.changeCase.pascal(name) %>
# this file's location depends on whether or not the css option is selected via the prompt
to: "<%= `static/usage/v${version}/${name.replace('ion-', '')}/${path}/${css ? 'react/main_tsx.md' : 'react.md'}` %>"
---
```tsx
import React from 'react';
import { <%= pascalName %> } from '@ionic/react';
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved

function Example() {
return (
<<%= pascalName %>></<%= pascalName %>>
);
}
export default Example;
```

9 changes: 9 additions & 0 deletions _templates/playground/new/react_main_css.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# this file only gets generated if `css` (from the command line prompt) is true
to: "<%= css ? `static/usage/v${version}/${name.replace('ion-', '')}/${path}/react/main_css.md` : null %>"
---
```css
<%= name %> {
/* styles go here */
}
```
27 changes: 27 additions & 0 deletions _templates/playground/new/vue.md.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
arbitrary: <% pascalName = h.changeCase.pascal(name) %>
to: "<%= `static/usage/v${version}/${name.replace('ion-', '')}/${path}/vue.md` %>"
---
```html
<template>
<<%= name %>>
</<%= name %>>
mapsandapps marked this conversation as resolved.
Show resolved Hide resolved
</template>

<script lang="ts">
import { <%= pascalName %> } from '@ionic/vue';
import { defineComponent } from 'vue';

export default defineComponent({
components: {
<%= pascalName %>,
},
});
</script><% if (css){ %>

<style scoped>
<%= name %> {
/* styles go here */
}
</style><% } %>
```
Loading