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

www: add language switcher to code blocks #1623

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
30 changes: 13 additions & 17 deletions docs/canary/concepts/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@ special [\_app](/docs/concepts/app-wrapper.md) wrapper and normal
properties, e.g. `ctx.state.loggedIn = true`, but you can also replace the
entire object like `ctx.state = { loggedIn = true }`.

```ts
// routes/_middleware.ts
import { MiddlewareHandlerContext } from "$fresh/server.ts";
```ts { "title": "routes/_middleware.ts" }
import type { MiddlewareHandlerContext } from "$fresh/server.ts";

interface State {
data: string;
}

export async function handler(
req: Request,
ctx: MiddlewareHandlerContext<State>,
ctx: MiddlewareHandlerContext<State>
) {
ctx.state.data = "myData";
const resp = await ctx.next();
Expand All @@ -36,8 +35,7 @@ export async function handler(
}
```

```ts
// routes/myHandler.ts
```ts { "title": "routes/myHandler.ts" }
export const handler: Handlers<any, { data: string }> = {
GET(_req, ctx) {
return new Response(`middleware data is ${ctx.state.data}`);
Expand All @@ -52,7 +50,7 @@ specific first).

For example, take a project with the following routes:

```
```txt { "title": "Project structure" }
└── routes
   ├── _middleware.ts
   ├── index.ts
Expand Down Expand Up @@ -85,9 +83,7 @@ A single middleware file can also define multiple middlewares (all for the same
route) by exporting an array of handlers instead of a single handler. For
example:

```ts
// routes/_middleware.ts

```ts { "title": "routes/_middleware.ts"}
export const handler = [
async function middleware1(req, ctx) {
// do something
Expand All @@ -103,8 +99,8 @@ export const handler = [
It should be noted that `middleware` has access to route parameters. If you're
running a fictitious `routes/[tenant]/admin/_middleware.ts` like this:

```ts
import { MiddlewareHandlerContext } from "$fresh/server.ts";
```ts { "title": "routes/[tenant]/admin/_middleware.ts" }
import type { MiddlewareHandlerContext } from "$fresh/server.ts";

export async function handler(_req: Request, ctx: MiddlewareHandlerContext) {
const currentTenant = ctx.params.tenant;
Expand All @@ -121,7 +117,7 @@ the value of `acme` in your middleware.

To set the stage for this section, `MiddlewareHandlerContext` looks like this:

```ts
```ts { "title": "Type definition", "lang_switcher": false}
export interface MiddlewareHandlerContext<State = Record<string, unknown>> {
next: () => Promise<Response>;
state: State;
Expand All @@ -136,7 +132,7 @@ export interface MiddlewareHandlerContext<State = Record<string, unknown>> {

and `router.DestinationKind` is defined like this:

```ts
```ts { "title": "Type definition", "lang_switcher": false}
export type DestinationKind = "internal" | "static" | "route" | "notFound";
```

Expand All @@ -148,8 +144,8 @@ for a `route`, as opposed to something like `http://localhost:8001/favicon.ico`.
Initiate a new Fresh project (`deno run -A -r https://fresh.deno.dev/`) and then
create a `_middleware.ts` file in the `routes` folder like this:

```ts
import { MiddlewareHandlerContext } from "$fresh/server.ts";
```ts { "title": "routes/_middleware.ts" }
import type { MiddlewareHandlerContext } from "$fresh/server.ts";

export async function handler(req: Request, ctx: MiddlewareHandlerContext) {
console.log(ctx.destination);
Expand All @@ -161,7 +157,7 @@ export async function handler(req: Request, ctx: MiddlewareHandlerContext) {

If you start up your server (`deno task start`) you'll see the following:

```
```sh { "title": "Terminal output"}
Task start deno run -A --watch=static/,routes/ dev.ts
Watcher Process started.
The manifest has been generated for 4 routes and 1 islands.
Expand Down
50 changes: 26 additions & 24 deletions docs/canary/concepts/route-groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ than another route that's in the same URL segment.

Let's illustrate that with an example:

```txt
```txt { "title": "Intended URL to layout mapping"}
/about -> layout A
/career -> layout A
/archive -> layout B
Expand All @@ -20,39 +20,41 @@ Let's illustrate that with an example:
Without any way to group routes this is a problem because every route segment
can only have one `_layout` file.

```txt
/routes
/_layout.tsx <-- applies to all routes here :(
/about.tsx
/career.tsx
/archive.tsx
/contact.tsx
```txt { "title": "Project structure "}
routes/
_layout.tsx <-- applies to all routes here :(
about.tsx
career.tsx
archive.tsx
contact.tsx
```

We can solve this problem with route groups. A route group is a folder which has
a name that is wrapped in braces. For example `(pages)` would be considered a
route and so would be `(marketing)`. This enables us to group related routes in
a folder and use a different `_layout` file for each group.

```txt
/routes
/(marketing)
/_layout.tsx <-- only applies to about.tsx and career.tsx
/about.tsx
/career.tsx
/(info)
/_layout.tsx <-- only applies to archive.tsx and contact.tsx
/archive.tsx
/contact.tsx
```txt { "title": "Project structure"}
routes/
(marketing)/
_layout.tsx <-- only applies to about.tsx and career.tsx
about.tsx
career.tsx

(info)/
_layout.tsx <-- only applies to archive.tsx and contact.tsx
archive.tsx
contact.tsx
```

> ℹ️ Be careful about routes in different groups which match to the same URL.
> Such scenarios will lead to ambiguity as to which route file should be picked.
>
> ```txt
> /routes
> /(group-1)
> /about.tsx <-- Bad: Both routes map to the same `/about` url
> /(group-2)
> /about.tsx <-- Bad: Both routes map to the same `/about` url
> ```txt { "title": "Project structure"}
> routes/
> (group-1)/
> about.tsx <-- Bad: Both routes map to the same `/about` url
>
> (group-2)/
> about.tsx <-- Bad: Both routes map to the same `/about` url
> ```
25 changes: 11 additions & 14 deletions docs/canary/concepts/route-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ An route layout is defined in a `_layout.tsx` file in any sub directory (at any
level) under the `routes/` folder. It must contain a default export that is a
regular Preact component. Only one such layout is allowed per sub directory.

```sh
```txt { "title": "Project structure" }
routes/
_app.tsx
_layout.tsx # will be applied to all routes
/sub
sub/
index.tsx
page.tsx
/other
other/
_layout.tsx # will be applied on top of `routes/_layout.tsx`
page.tsx
```
Expand All @@ -24,10 +24,8 @@ things. This allows for the introduction of a global container functioning as a
template which can be conditioned based on state and params. Note that any state
set by middleware is available via `props.state`.

```tsx
// routes/sub/_layout.tsx

import { LayoutProps } from "$fresh/server.ts";
```tsx { "title": "routes/sub/_layout.tsx" }
import type { LayoutProps } from "$fresh/server.ts";

export default function Layout({ Component, state }: LayoutProps) {
//do something with state here
Expand All @@ -45,10 +43,10 @@ Sometimes you want to opt out of the layout inheritance mechanism for a
particular route. This can be done via route configuration. Picture a directory
structure like this:

```sh
```txt { "title": "Project structure" }
routes/
_layout.tsx
/sub
sub/
_layout.tsx
index.tsx
special.tsx # should not inherit layouts
Expand All @@ -57,9 +55,8 @@ routes/
To make `routes/sub/special.tsx` opt out of rendering layouts we can set
`rootLayout: true`.

```tsx
// routes/sub/special.tsx
import { RouteConfig } from "$fresh/server.ts";
```tsx { "title": "routes/sub/special.tsx"}
import type { RouteConfig } from "$fresh/server.ts";

export const config: RouteConfig = {
rootLayout: true, // Mark this route as the root layout
Expand All @@ -77,8 +74,8 @@ Note that you can also mark layouts as root layouts.
In very rare cases you might want to disable the root `_app` template for a
particular route. This can be done by setting `appTemplate: false`.

```tsx
import { RouteConfig } from "$fresh/server.ts";
```tsx { "title": "routes/my-page.tsx"}
import type { RouteConfig } from "$fresh/server.ts";

export const config: RouteConfig = {
appTemplate: false, // Disable the `_app` template
Expand Down
6 changes: 2 additions & 4 deletions docs/latest/concepts/app-wrapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ things. This allows for the introduction of a global container functioning as a
template which can be conditioned based on state and params. Note that any state
set by middleware is available via `props.state`.

```tsx
// routes/_app.tsx

import { AppProps } from "$fresh/server.ts";
```tsx { "title": "routes/_app.tsx" }
import type { AppProps } from "$fresh/server.ts";

export default function App({ Component, state }: AppProps) {
//do something with state here
Expand Down
2 changes: 1 addition & 1 deletion docs/latest/concepts/data-fetching.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ component through the `data` property on the `props`.

Here is an example:

```tsx
```tsx { "title": "routes/projects/[id].tsx" }
interface Project {
name: string;
stars: number;
Expand Down
6 changes: 3 additions & 3 deletions docs/latest/concepts/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ caching **will** cause your project to not function correctly.

Here is an example `Dockerfile` for a Fresh project:

```dockerfile
```dockerfile { "title": "Dockerfile" }
FROM denoland/deno:1.35.0

ARG GIT_REVISION
Expand All @@ -53,13 +53,13 @@ CMD ["run", "-A", "main.ts"]

To build your Docker image inside of a Git repository:

```sh
```sh { "title": "Terminal output" }
$ docker build --build-arg GIT_REVISION=$(git rev-parse HEAD) -t my-fresh-app .
```

Then run your Docker container:

```sh
```sh { "title": "Terminal output" }
$ docker run -t -i -p 80:8000 my-fresh-app
```

Expand Down
12 changes: 6 additions & 6 deletions docs/latest/concepts/error-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ The 404 page can be customized by creating a `_404.tsx` file in the `routes/`
folder. The file must have a default export that is a regular Preact component.
A props object of type `UnknownPageProps` is passed in as an argument.

```tsx
import { UnknownPageProps } from "$fresh/server.ts";
```tsx { "title": "routes/_404.tsx" }
import type { UnknownPageProps } from "$fresh/server.ts";

export default function NotFoundPage({ url }: UnknownPageProps) {
return <p>404 not found: {url.pathname}</p>;
Expand All @@ -29,8 +29,8 @@ In some cases, one needs to manually trigger the rendering of the 404 page, for
example when the route did match, but the requested resource does not exist.
This can be achieved with `ctx.renderNotFound`.

```tsx
import { Handlers, PageProps } from "$fresh/server.ts";
```tsx { "title": "routes/blog/[slug].tsx" }
import type { Handlers, PageProps } from "$fresh/server.ts";

export const handler: Handlers = {
async GET(req, ctx) {
Expand Down Expand Up @@ -60,8 +60,8 @@ The 500 page can be customized by creating a `_500.tsx` file in the `routes/`
folder. The file must have a default export that is a regular Preact component.
A props object of type `ErrorPageProps` is passed in as an argument.

```tsx
import { ErrorPageProps } from "$fresh/server.ts";
```tsx { "title": "routes/_500.tsx" }
import type { ErrorPageProps } from "$fresh/server.ts";

export default function Error500Page({ error }: ErrorPageProps) {
return <p>500 internal error: {(error as Error).message}</p>;
Expand Down
5 changes: 2 additions & 3 deletions docs/latest/concepts/forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ or as a `POST` request with `multipart/form-data`.
This example demonstrates how to handle `multipart/form-data` `<form>`
submissions:

```tsx
// routes/subscribe.tsx
import { Handlers } from "$fresh/server.ts";
```tsx { "title": "routes/subscribe.tsx" }
import { type Handlers } from "$fresh/server.ts";

export const handler: Handlers = {
async GET(req, ctx) {
Expand Down
13 changes: 4 additions & 9 deletions docs/latest/concepts/islands.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ Islands are defined by creating a file in the `islands/` folder in a Fresh
project. The name of this file must be a PascalCase or kebab-case name of the
island.

```tsx
// islands/MyIsland.tsx

```tsx { "title": "islands/MyIsland.tsx" }
import { useSignal } from "@preact/signals";

export default function MyIsland() {
Expand Down Expand Up @@ -53,8 +51,7 @@ functions is not supported.
Islands support passing JSX elements via the `children` property. This allows
you to pass static content rendered by the server to an island in the browser.

```jsx
// route/index.tsx
```tsx { "title": "route/index.tsx" }
import MyIsland from "../islands/my-island.tsx";

export default function Home() {
Expand All @@ -77,8 +74,7 @@ Islands can be nested within other islands as well. In that scenario they act
like a normal Preact component, but still receive the serialized props if any
were present.

```jsx
// route/index.tsx
```tsx { "title": "route/index.tsx" }
import MyIsland from "../islands/my-island.tsx";
import OtherIsland from "../islands/other-island.tsx";

Expand All @@ -97,8 +93,7 @@ In essence, Fresh allows you to mix static and interactive parts in your app in
a way that's most optimal for your use app. We'll keep sending only the
JavaScript that is needed for the islands to the browser.

```jsx
// route/index.tsx
```tsx { "title": "route/index.tsx"}
import MyIsland from "../islands/my-island.tsx";
import OtherIsland from "../islands/other-island.tsx";

Expand Down
Loading