Skip to content

Commit 414385b

Browse files
committed
WIP: Interactive Playgrounds
- Support the `-components` flag on `dsk`, to allow passing a path to a pre-build component bundle output directory. - Provide playground handlers. - Refactor `<Playground>` - Use IFrame in Playground Unrelated: - Deprecate Node.components response property. - Improve routing techniques, by using sub routers and allow us to extract route params. - Rename flag variables. - Pass more parent and current node into documentation components. - Nodes now have an `id` that can be used to adress them. Although not from the outside.
1 parent 0593347 commit 414385b

File tree

27 files changed

+572
-242
lines changed

27 files changed

+572
-242
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 1.4.0
44

5+
- Components of a user provided component library can now be used inside
6+
`<Playground>` to create interactive demos of components.
57
- Support _Table of Contents_ on documents.
68
- Introduced new `<ImageGrid>` documentation component.
79

CONTRIBUTING.md

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ the `frontend/build` directory by default.
2020

2121
## Prerequisites
2222

23-
[Go](https://golang.org/) version 1.11 or later is needed for developing
23+
[Go](https://golang.org/) version 1.16 or later is needed for developing
2424
and testing the application. [Node.js](https://nodejs.org) and
2525
[Yarn](https://yarnpkg.com) are needed to build the built-in frontend.
2626

@@ -31,67 +31,51 @@ directory to your `PATH`, so that go binaries can be found. In
3131
export PATH=$PATH:$(go env GOPATH)/bin
3232
```
3333

34-
DSK uses `go mod` to manage its dependencies. When using
35-
Go 1.11 module support must be explictly enabled, add this line to
36-
`.profile`:
37-
```
38-
export GO111MODULE=on
39-
```
40-
4134
## Setup
4235

43-
Clone the official repository, switch into the directory and checkout the branch
44-
you want to work on.
36+
First we'll be setting up an umbrella directory where the main dsk repository
37+
and supporting repositories will live, which we'll clone into it.
4538

4639
```
47-
$ git clone github.com/rundsk/dsk
48-
$ git checkout 1.2
49-
$ cd dsk
50-
```
40+
mkdir rundsk
41+
cd rundsk
5142
52-
When using the built-in frontend, the `frontend/build` folder must be
53-
present and contain the compiled version of the frontend. After a new
54-
checkout you can create it, using the following command.
55-
56-
```
57-
$ make -C frontend build
43+
git clone git@github.com:rundsk/dsk.git
44+
git clone git@github.com:rundsk/js-sdk.git
45+
git clone git@github.com:rundsk/example-component-library.git
46+
git clone git@github.com:rundsk/example-design-system.git
5847
```
5948

60-
## Improving the frontend
61-
62-
There are two ways to work on the built-in frontend and verify changes
63-
in your browser easily at the same time while you go.
49+
All the following documentation will assume that you are working from inside the
50+
main repository checkout.
6451

65-
First start the backend which will also serve the frontend.
6652
```
67-
$ make dev
53+
cd dsk
6854
```
6955

70-
Each time you change the source of the frontend run the following
71-
command and reload the browser window to see the changes.
56+
## Developing
7257

73-
```
74-
$ make -C frontend build
75-
```
58+
First we'll start the backend in development mode and after that do the same
59+
with the frontend.
7660

77-
Alternatively you can start the frontend (using a development server)
78-
and the backend separately on different ports, having the frontend use
79-
backend over its HTTP API.
61+
On a fresh checkout we'll have to install the dependencie of the frontend
62+
first, and then start the frontend's development server.
8063

81-
Start the backend, first. By default it'll be reachable over port 8080.
8264
```
83-
$ make dev
65+
cd frontend
66+
yarn
67+
make dev
8468
```
8569

86-
Second, start the frontend using a development server. It will be
87-
reachable over port 3000 and proxy requests through to the backend.
70+
You should now be able to reach the frontend when opening http://127.0.0.1:3000
71+
in your browser. You might see some errors as we not yet have started the backend.
72+
73+
Now inside another terminal we'll start the backend.
8874

8975
```
90-
$ make -C frontend dev
76+
make dev
9177
```
9278

93-
Now open http://127.0.0.1:3000 in your browser.
94-
9579
## Debugging
9680

9781
When running the tests the search indexes are store to disk, to ease

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
FRONTEND ?= $(shell pwd)/frontend/build
88
DDT ?= $(shell pwd)/../example-design-system
9+
COMPONENTS ?= $(shell pwd)/../example-component-library/build
910

1011
VERSION ?= head-$(shell git rev-parse --short HEAD)
1112
LDFLAGS = -X main.Version=$(VERSION)
@@ -32,7 +33,7 @@ lint:
3233
.PHONY: dev
3334
dev:
3435
go build -tags=dev -ldflags "$(LDFLAGS)" $(CMD_PKG)
35-
./dsk -frontend $(FRONTEND) "$(DDT)"
36+
./dsk -frontend $(FRONTEND) -components $(COMPONENTS) "$(DDT)"
3637
rm dsk
3738

3839
.PHONY: clean

cmd/dsk/main.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@ func main() {
5858
}
5959
}()
6060

61-
host := flag.String("host", "127.0.0.1", "host IP to bind to")
62-
port := flag.String("port", "8080", "port to bind to")
63-
version := flag.Bool("version", false, "print DSK version")
64-
noColor := flag.Bool("no-color", false, "disables color output")
61+
fhost := flag.String("host", "127.0.0.1", "host IP to bind to")
62+
fport := flag.String("port", "8080", "port to bind to")
63+
fversion := flag.Bool("version", false, "print DSK version")
64+
fnoColor := flag.Bool("no-color", false, "disables color output")
65+
fcomponents := flag.String("components", "", "path to component library assets")
6566
ffrontend := flag.String("frontend", "", "path to a frontend, to use instead of the built-in")
6667
fallowOrigin := flag.String("allow-origin", "", "origins from which browsers can access the HTTP API; for multiple origins, use a comma as a separator, the wildcard * is supported; to allow all use *")
6768
flag.Parse()
@@ -70,14 +71,14 @@ func main() {
7071
log.Fatalf("Too many arguments given, expecting exactly 0 or 1")
7172
}
7273

73-
if *version {
74+
if *fversion {
7475
fmt.Println(Version)
7576
os.Exit(1)
7677
}
7778

7879
// Color package automatically disables colors when not a TTY. We
7980
// don't need to check for an interactive terminal here again.
80-
if *noColor {
81+
if *fnoColor {
8182
color.NoColor = true
8283
}
8384
whiteOnBlue := color.New(color.FgWhite, color.BgBlue)
@@ -114,7 +115,17 @@ func main() {
114115
if err != nil {
115116
panic(err)
116117
}
117-
log.Printf("Detected live path: %s", livePath)
118+
log.Printf("Using live path: %s", livePath)
119+
120+
var componentsPath string
121+
if *fcomponents != "" {
122+
componentsPath = *fcomponents
123+
}
124+
125+
var frontendPath string
126+
if *ffrontend != "" {
127+
frontendPath = *ffrontend
128+
}
118129

119130
allowOrigins := strings.Split(*fallowOrigin, ",")
120131
if len(allowOrigins) != 0 {
@@ -124,7 +135,8 @@ func main() {
124135
app = plex.NewApp( // assign to global
125136
Version,
126137
livePath,
127-
*ffrontend,
138+
componentsPath,
139+
frontendPath,
128140
)
129141
ctx, cancel := context.WithCancel(context.Background())
130142
app.Teardown.AddCancelFunc(cancel)
@@ -133,6 +145,12 @@ func main() {
133145
log.Fatal(red.Sprintf("Failed to initialize application: %s", err))
134146
}
135147

148+
if componentsPath != "" {
149+
if err := app.OpenComponents(ctx); err != nil {
150+
log.Print(red.Sprintf("Failed to start application: %s", err))
151+
}
152+
}
153+
136154
if app.HasMultiVersionsSupport() {
137155
log.Printf("Detected support for multi-versions")
138156

@@ -145,7 +163,7 @@ func main() {
145163

146164
apis := map[int]httputil.Mountable{
147165
1: api.NewV1(app.Sources, app.Version, app.Broker, allowOrigins),
148-
2: api.NewV2(app.Sources, app.Version, app.Broker, allowOrigins),
166+
2: api.NewV2(app.Sources, app.Components, app.Version, app.Broker, allowOrigins),
149167
}
150168
for av, a := range apis {
151169
log.Printf("Mounting APIv%d HTTP mux...", av)
@@ -159,7 +177,7 @@ func main() {
159177
log.Print("Mounting frontend HTTP mux...")
160178
mux.Handle("/", app.Frontend.HTTPMux())
161179

162-
addr := fmt.Sprintf("%s:%s", *host, *port)
180+
addr := fmt.Sprintf("%s:%s", *fhost, *fport)
163181
if isTerminal {
164182
log.Print("-------------------------------------------")
165183
log.Printf("Please visit: %s", green.Sprint("http://"+addr))

frontend/src/Breadcrumbs/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function Breadcrumbs(props) {
1414
let crumbs;
1515

1616
if (props.crumbs) {
17-
crumbs = props.crumbs.map(c => {
17+
crumbs = props.crumbs.map((c) => {
1818
return (
1919
<li className="breadcrumbs__crumb" key={c.title}>
2020
<BaseLink
@@ -25,7 +25,6 @@ function Breadcrumbs(props) {
2525
>
2626
{c.title}
2727
</BaseLink>
28-
{/* <a href={`/tree/${c.url}`}>{c.title}</a> */}
2928
</li>
3029
);
3130
});

frontend/src/CodeBlock/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function CodeBlock(props) {
5959

6060
useEffect(() => {
6161
if (props.src) {
62-
Client.fetch(props.src, 'text').then(data => setCode(<code className="code-block__code-content">{data}</code>));
62+
Client.fetch(props.src, 'text').then((data) => setCode(<code className="code-block__code-content">{data}</code>));
6363
} else {
6464
let content;
6565

frontend/src/Doc/index.js

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,47 +46,51 @@ function Doc(props) {
4646
return <div className="doc">{props.children}</div>;
4747
}
4848

49-
// Allow to use this inside the `transforms` constant. We cannot use
50-
// `props.title` there as that refers to the component/element that is being
51-
// transformed. The title is needed as to calculate the `Heading`'s jump
52-
// anchor.
53-
let docTitle = props.title;
49+
// Transform context: Allow to use this inside the `transforms` constant. We
50+
// cannot use `props.x` there as that refers to the component/element that is
51+
// being transformed.
52+
let context = {
53+
node: props.node,
54+
doc: { id: props.id, url: props.url, title: props.title },
55+
};
5456

5557
const transforms = {
56-
Banner: props => <Banner {...props} />,
57-
CodeBlock: props => {
58+
Banner: (props) => <Banner {...props} />,
59+
CodeBlock: (props) => {
5860
// When using <CodeBlock> directly within documents, its contents aren't
5961
// automatically protected from interpration as HTML, when they processed
6062
// by the DocTransformer. Thus we expect users to wrap their literal code
6163
// in <script> tags, which we again remove here.
6264
let children = props.children.replace(/^\s*<script>/, '').replace(/<\/script>\s*$/, '');
6365

64-
return <CodeBlock {...props} children={children} />;
66+
return <CodeBlock {...props} {...context} children={children} />;
6567
},
66-
ColorCard: props => <ColorCard {...props} />,
67-
ColorGroup: props => <ColorGroup {...props} />,
68-
Color: props => <Color {...props} />,
69-
Playground: props => <Playground {...props} />,
70-
Do: props => <Do {...props} />,
71-
DoDontGroup: props => <DoDont {...props} />,
72-
Dont: props => <Dont {...props} />,
73-
FigmaEmbed: props => <FigmaEmbed {...props} />,
74-
Image: props => <Image {...props} />,
75-
TypographySpecimen: props => <TypographySpecimen {...props} />,
76-
Warning: props => <Banner type="warning" {...props} />,
77-
Glitch: props => <Glitch {...props} />,
78-
CodeSandbox: props => <CodeSandbox {...props} />,
79-
Asciinema: props => <Asciinema {...props} />,
80-
ImageGrid: props => <ImageGrid {...props} />,
81-
TableOfContents: props => <TableOfContents {...props} docTitle={docTitle} />,
82-
83-
a: props => <Link {...props} />,
84-
h1: props => <Heading {...props} level="alpha" docTitle={docTitle} isJumptarget={true} />,
85-
h2: props => <Heading {...props} level="beta" docTitle={docTitle} isJumptarget={true} />,
86-
h3: props => <Heading {...props} level="gamma" docTitle={docTitle} isJumptarget={true} />,
87-
h4: props => <Heading {...props} level="delta" docTitle={docTitle} isJumptarget={true} />,
88-
img: props => <Image {...props} />,
89-
pre: props => {
68+
ColorCard: (props) => <ColorCard {...props} {...context} />,
69+
ColorGroup: (props) => <ColorGroup {...props} {...context} />,
70+
Color: (props) => <Color {...props} {...context} />,
71+
Playground: (props) => <Playground {...props} {...context} />,
72+
Do: (props) => <Do {...props} {...context} />,
73+
DoDontGroup: (props) => <DoDont {...props} {...context} />,
74+
Dont: (props) => <Dont {...props} {...context} />,
75+
FigmaEmbed: (props) => <FigmaEmbed {...props} {...context} />,
76+
Image: (props) => <Image {...props} {...context} />,
77+
TypographySpecimen: (props) => <TypographySpecimen {...props} {...context} />,
78+
Warning: (props) => <Banner type="warning" {...props} {...context} />,
79+
Glitch: (props) => <Glitch {...props} {...context} />,
80+
CodeSandbox: (props) => <CodeSandbox {...props} {...context} />,
81+
Asciinema: (props) => <Asciinema {...props} {...context} />,
82+
ImageGrid: (props) => <ImageGrid {...props} {...context} />,
83+
TableOfContents: (props) => <TableOfContents {...props} {...context} />,
84+
85+
a: (props) => <Link {...props} {...context} />,
86+
87+
h1: (props) => <Heading {...props} {...context} level="alpha" isJumptarget={true} />,
88+
h2: (props) => <Heading {...props} {...context} level="beta" isJumptarget={true} />,
89+
h3: (props) => <Heading {...props} {...context} level="gamma" isJumptarget={true} />,
90+
h4: (props) => <Heading {...props} {...context} level="delta" isJumptarget={true} />,
91+
92+
img: (props) => <Image {...props} {...context} />,
93+
pre: (props) => {
9094
// When a language is added to a Markdown fenced code block, it is
9195
// stored as a class with a "language-" prefix in the inner <code>.
9296
// Here we extract it and turn it into a prop.
@@ -101,18 +105,18 @@ function Doc(props) {
101105
// empty "ghost" elements.
102106
let children = props.children.replace(/^<code>/, '').replace(/<\/code>$/, '');
103107

104-
return <CodeBlock escaped {...props} children={children} />;
108+
return <CodeBlock escaped {...props} {...context} children={children} />;
105109
},
106110
};
107111

108112
const orphans = Object.keys(transforms)
109-
.filter(k => k !== 'a')
110-
.filter(k => k !== 'Color')
111-
.map(k => `p > ${k}`)
113+
.filter((k) => k !== 'a')
114+
.filter((k) => k !== 'Color')
115+
.map((k) => `p > ${k}`)
112116
.concat(['p > video']);
113117

114118
let transformedContent = transform(props.htmlContent, transforms, orphans, {
115-
isPreformatted: type => type === 'pre' || type === 'CodeBlock'.toLowerCase(),
119+
isPreformatted: (type) => ['pre', 'CodeBlock', 'Playground'].map((v) => v.toLowerCase()).includes(type),
116120
noTransform: (type, props) => {
117121
// This gets called on HTML elements that do not need
118122
// to be transformed to special React components.

frontend/src/Heading/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ function Heading(props) {
2828

2929
let id = slugify(getNodeText(props.children));
3030

31-
let handleClick = ev => {
31+
let handleClick = (ev) => {
3232
ev.preventDefault();
3333

3434
let currentRouterState = props.router.getState();
3535
let currentNode = currentRouterState.params.node || '';
36-
let t = slugify(props.docTitle) + '§' + id;
36+
let t = slugify(props.doc.title) + '§' + id;
3737

3838
props.router.navigate(
3939
'node',
@@ -59,7 +59,7 @@ function Heading(props) {
5959

6060
export default withRoute(Heading);
6161

62-
const getNodeText = node => {
62+
const getNodeText = (node) => {
6363
if (['string', 'number'].includes(typeof node)) return node;
6464
if (node instanceof Array) return node.map(getNodeText).join('');
6565
if (typeof node === 'object' && node) return getNodeText(node.props.children);

0 commit comments

Comments
 (0)