Skip to content

Commit

Permalink
Add Cookbook (#214)
Browse files Browse the repository at this point in the history
* Centralize site header; add cookbook route

* Get cookin’!

* Revert types + placeholder article

* Cleanup

* Cleanup

* React to Enhance

Signed-off-by: macdonst <[email protected]>

* Spell check

Signed-off-by: macdonst <[email protected]>

* Shorter code block

Signed-off-by: macdonst <[email protected]>

* Update React recipe

* Update navdata

* Update redirects

* Add typescript recipe

Signed-off-by: macdonst <[email protected]>

* Update TS recipe

* Update Cookbook for dark mode

---------

Signed-off-by: macdonst <[email protected]>
Co-authored-by: macdonst <[email protected]>
  • Loading branch information
colepeters and macdonst committed Jun 6, 2024
1 parent ae62dde commit 8315f1b
Show file tree
Hide file tree
Showing 33 changed files with 880 additions and 170 deletions.
6 changes: 6 additions & 0 deletions app/api/cookbook.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export async function get () {
return {
statusCode: 301,
location: '/cookbook/',
}
}
64 changes: 64 additions & 0 deletions app/api/cookbook/$$.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-disable filenames/match-regex */
import { readFileSync } from 'fs'
import { URL } from 'url'
import { Arcdown } from 'arcdown'
import arcStaticImg from 'markdown-it-arc-static-img'
import navDataLoader, {
other as otherLinks,
} from '../../docs/nav-data.mjs'
import HljsLineWrapper from '../../docs/hljs-line-wrapper.mjs'

const arcdown = new Arcdown({
pluginOverrides: {
markdownItToc: {
containerClass: 'toc mbe2 mis-2 leading2',
listType: 'ul',
level: [ 1, 2, 3 ],
},
},
plugins: [ arcStaticImg ],
hljs: {
sublanguages: { javascript: [ 'xml', 'css' ] },
plugins: [ new HljsLineWrapper({ className: 'code-line' }) ],
},
})

/** @type {import('@enhance/types').EnhanceApiFn} */
export async function get (request) {
const { path: activePath } = request
let recipePath = activePath.replace(/^\/?docs\//, '') || 'index'

let recipeURL = new URL(`../../${recipePath}.md`, import.meta.url)

const navData = navDataLoader('docs', activePath)

let recipeMarkdown
try {
recipeMarkdown = readFileSync(recipeURL.pathname, 'utf-8')
}
catch (e) {
return {
location: '/404'
}
}

const recipe = await arcdown.render(recipeMarkdown)

const initialState = {
recipe,
otherLinks,
navData,
}

let cacheControl =
process.env.ARC_ENV === 'production'
? 'max-age=3600;'
: 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0'

return {
headers: {
'cache-control': cacheControl,
},
json: initialState,
}
}
21 changes: 21 additions & 0 deletions app/api/cookbook/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import navDataLoader from '../../docs/nav-data.mjs'

export async function get (req) {
const { path: activePath } = req

const cacheControl =
process.env.ARC_ENV === 'production'
? 'max-age=3600'
: 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0'

const navData = navDataLoader('docs', activePath)

return {
headers: {
'cache-control': cacheControl,
},
json: {
navData,
},
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Building for the browser
title: Build for the browser
---

## The `@bundles` plugin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
---
title: Architect Migration
links:
- "arc.codes": https://arc.codes
title: Migrate from Architect
---

Enhance uses [Architect](https://arc.codes) under the hood for local development and deployment. It is possible to migrate between a typical Architect project structure and the Enhance file-based routing. It is also possible to mix the two approaches together in the same app. They are incrementally adoptable in both directions.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
---
title: Rendering Markdown
links:
- "Arcdown": https://github.com/architect/arcdown/blob/main/readme.md
title: Render Markdown
---

Enhance can be used to render Markdown with minimal effort — in fact, this very site is itself an Enhance app that renders Markdown to HTML on demand. You can dig into the [source code](https://github.com/enhance-dev/enhance.dev) to see exactly how we've set it up, or follow along below.
Expand Down
84 changes: 84 additions & 0 deletions app/cookbook/translate-react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: Translate React syntax to Enhance elements
---

We’re often asked by React developers why patterns they’ve learned while writing JSX don’t translate to writing web components. In this doc, we’ll describe some common gotchas that developers coming from React or other JavaScript frameworks may run into when writing plain vanilla web components.

## String Interpolation

<code-compare>

<doc-code filename="JavaScript">

```javascript
const element = `<h1>${title}</h1>`;
```

</doc-code>


<doc-code filename="React">

```javascript
const element = <h1>{title}</h1>;
```

</doc-code>

</code-compare>

## Attribute Quoting

<code-compare>

<doc-code filename="JavaScript">

```javascript
const image = `<img src="${href}" />`;
```

</doc-code>


<doc-code filename="React">

```javascript
const image = <img src={href} />
```

</doc-code>

</code-compare>

## Rendering Markup from Arrays

<code-compare>

<doc-code filename="JavaScript">

```javascript
const todoList = `<ul>
${todos.map((todo) => (
`<li key="${todo.id}">${todo.text}</li>`
))}
</ul>`
```

</doc-code>


<doc-code filename="React">

```javascript
const todoList = <ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
```

</doc-code>

</code-compare>

For a more in depth look at the differences between Enhance and React components, [read this post on the Begin blog](https://begin.com/blog/posts/2024-03-08-a-react-developers-guide-to-writing-enhance-components).
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Event Listeners
title: Use event listeners
---

An event is a signal that something has happened on your page. The browser notifies you so you can react to them.
Expand Down
104 changes: 104 additions & 0 deletions app/cookbook/use-typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
title: Use TypeScript
---

If you prefer to work with TypeScript, we recommend starting with our [TypeScript starter project](https://github.com/enhance-dev/enhance-starter-typescript).


## Getting Started

Assuming you’re starting a new Enhance project, you would run the command:

```bash
npx "@enhance/cli@latest" new ./myproject \
--template https://github.com/enhance-dev/enhance-starter-typescript -y
```

This will set up a new Enhance project where you’ll code your APIs, elements and pages in TypeScript instead of JavaScript. Instead of editing files in the `app` folder, you’ll do your editing in the `ts` folder.


### Project Structure

``` \
ts
├── api ............... data routes
│ └── index.mts
├── browser ........... browser JavaScript
│ └── index.mts
├── components ........ single file web components
│ └── my-card.mts
├── elements .......... custom element pure functions
│ └── my-header.mts
├── pages ............. file-based routing
│ └── index.html
└── head.mts .......... custom <head> component
```

Note: We are using `.mts` to tell the TypeScript Compiler to generate ES Modules as `.mjs` files..


## Local Development

Running the local development environment is the same as any other Enhance project. The new `@enhance/plugin-typescript` is responsible for watching the `ts` folder for any file changes. If a file with an `.mts` extension is updated, it will be re-compiled with the compilation target being the `app` folder. All other file types are simply copied to their corresponding locations in the `app` folder.

## Authoring Code

Write your code in TypeScript. We already have [types](https://github.com/enhance-dev/types) that you can import into your elements:

<begin-code filename="ts/api/todo-item.mts">

```typescript
import type { EnhanceElemArg } from "@enhance/types"

export default ({ html, state: { attrs } }: EnhanceElemArg) => {
const { state = "" } = attrs
return html`
${state === "complete" ? "" : ""}
<slot></slot>
`
}
```

</begin-code>

Or APIs:

<begin-code filename="ts/api/todos.mts">

```typescript
import type {
EnhanceApiFn,
EnhanceApiReq,
EnhanceApiRes,
} from "@enhance/types";

type Todo = {
title: string;
completed?: boolean;
};

export const get: EnhanceApiFn = async function (
request: EnhanceApiReq,
): Promise<EnhanceApiRes> {

console.log(`Handling ${request.path}...`);

const todos: Todo[] = [
{ title: "todo 1", completed: false },
{ title: "todo 2", completed: true },
{ title: "todo 3" },
];

const response: EnhanceApiRes = {
json: { todos },
};

return response;
};
```

</begin-code>

## Deploying

Use the [`@begin/deploy`](https://begin.com/deploy/docs/workflows/deploying-code) package to deploy your application. Alternatively, you can write a GitHub Action to [deploy on every commit](https://github.com/enhance-dev/enhance-starter-typescript/blob/main/.github/workflows/CI.yml).
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Form Validation
title: Validate forms
---

HTML forms are very powerful on their own.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Testing
title: Write unit tests
---

A big benefit of Enhance custom element [pure functions](https://en.wikipedia.org/wiki/Pure_function) is that they return a string that you can test against an expected output. It doesn't need to get any more complicated than that to get started.
Expand Down
44 changes: 0 additions & 44 deletions app/docs/md/patterns/testing/webdriverio.md

This file was deleted.

11 changes: 0 additions & 11 deletions app/docs/nav-data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,6 @@ export const data = [
slug: 'patterns',
items: [
'progressive-enhancement',
'building-for-the-browser',
'form-validation',
{
slug: 'testing',
path: '/docs/patterns/testing/',
hasChildren: true,
items: [ { slug: 'webdriverio', label: 'WebdriverIO' } ],
},
'architect-migration',
'rendering-markdown',
'event-listeners',
],
},
/*
Expand Down
Loading

0 comments on commit 8315f1b

Please sign in to comment.