Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
File renamed without changes.
2 changes: 1 addition & 1 deletion docs/latest/examples/common-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export const handler = define.handlers({
## WebSockets

Fresh provides first-class WebSocket support via `ctx.upgrade()`. See the full
[WebSocket guide](/docs/examples/websockets) for all options.
[WebSocket guide](/docs/advanced/websockets) for all options.

## Subdomain routing

Expand Down
1 change: 0 additions & 1 deletion docs/latest/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ that you may like in your Fresh project.
- [Sharing state between islands](./examples/sharing-state-between-islands)
- [Active links](./examples/active-links)
- [Session management](./examples/session-management)
- [WebSockets](./examples/websockets)
- [Common Patterns](./examples/common-patterns)
2 changes: 1 addition & 1 deletion docs/toc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const toc: RawTableOfContents = {
["environment-variables", "Environment Variables", "link:latest"],
["head", "<head> element", "link:latest"],
["vite", "Vite Plugin Options", "link:latest"],
["websockets", "WebSockets", "link:latest"],
["opentelemetry", "OpenTelemetry", "link:latest"],
["api-reference", "API Reference", "link:latest"],
["troubleshooting", "Troubleshooting", "link:latest"],
Expand Down Expand Up @@ -107,7 +108,6 @@ const toc: RawTableOfContents = {
],
["active-links", "Active links", "link:latest"],
["session-management", "Session management", "link:latest"],
["websockets", "WebSockets", "link:latest"],
["common-patterns", "Common Patterns", "link:latest"],
],
},
Expand Down
2 changes: 1 addition & 1 deletion www/components/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function CodeBlock(
) {
return (
<pre
class="rounded-lg text-base leading-relaxed bg-slate-800 text-white p-4 sm:p-6 md:p-4 lg:p-6 2xl:p-8 overflow-x-auto"
class="rounded-lg text-sm leading-relaxed bg-slate-800 text-white p-3 sm:p-4 overflow-x-auto"
data-language={lang}
// deno-lint-ignore react-no-danger
><code dangerouslySetInnerHTML={{ __html: Prism.highlight(code, Prism.languages[lang], lang)}} /></pre>
Expand Down
4 changes: 2 additions & 2 deletions www/components/CodeWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function CodeWindow(props: CodeWindowProps) {
style={props.style}
>
<div class="flex items-stretch justify-start">
<div class="p-4 flex items-center">
<div class="p-3 flex items-center">
<svg
aria-hidden="true"
width="41"
Expand All @@ -28,7 +28,7 @@ export function CodeWindow(props: CodeWindowProps) {
<ellipse cx="35.9134" cy="5" rx="4.99155" ry="5" fill="#26C940" />
</svg>
</div>
<div class="p-4 w-full leading-none text-slate-400 text-base font-mono">
<div class="p-3 w-full leading-none text-slate-400 text-sm font-mono">
{props.name ?? ""}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion www/components/PageSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export function PageSection(props: JSX.HTMLAttributes<HTMLDivElement>) {
return (
<section
id={props.id ?? ""}
class={`w-full max-w-screen-xl mx-auto my-16 md:my-24 lg:my-32 px-4 sm:px-8 lg:px-16 2xl:px-0 flex flex-col gap-8 md:gap-16 ${
class={`w-full max-w-screen-xl mx-auto my-12 md:my-16 lg:my-24 px-4 sm:px-8 lg:px-16 2xl:px-0 flex flex-col gap-6 md:gap-8 ${
props.class ?? ""
}`}
>
Expand Down
2 changes: 1 addition & 1 deletion www/components/SideBySide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function SideBySide(props: SideBySideProps) {

return (
<div
class={`grid grid-cols-1 items-center gap-12 md:gap-16 xl:gap-32 ${
class={`grid grid-cols-1 items-center gap-8 md:gap-10 xl:gap-16 ${
props.reverseOnDesktop ? "[&>*]:md:first:order-1" : ""
} ${mdSplitClass} ${lgSplitClass} ${props.class ?? ""}`}
>
Expand Down
84 changes: 84 additions & 0 deletions www/components/homepage/APIRoutesSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { CodeBlock } from "../../components/CodeBlock.tsx";
import { CodeWindow } from "../../components/CodeWindow.tsx";
import { PageSection } from "../../components/PageSection.tsx";
import { SideBySide } from "../../components/SideBySide.tsx";
import { SectionHeading } from "../../components/homepage/SectionHeading.tsx";
import { FancyLink } from "../../components/FancyLink.tsx";

const apiCode = `import { createDefine } from "fresh";
const define = createDefine();

export const handlers = define.handlers({
GET(ctx) {
const user = db.getUser(ctx.params.id);
return Response.json(user);
},
POST(ctx) {
const body = await ctx.req.json();
const user = db.updateUser(ctx.params.id, body);
return Response.json(user);
},
DELETE(ctx) {
db.deleteUser(ctx.params.id);
return new Response(null, { status: 204 });
},
});`;

export function APIRoutesSection() {
return (
<PageSection>
<SideBySide
mdColSplit="3/2"
lgColSplit="3/2"
reverseOnDesktop
class="!items-start"
>
<div class="flex flex-col gap-4 md:sticky md:top-4">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-api text-fresh"
width="2.5rem"
height="2.5rem"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<title>API routes icon</title>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M4 13h5" />
<path d="M12 16v-8h3a2 2 0 0 1 2 2v1a2 2 0 0 1 -2 2h-3" />
<path d="M20 8v8" />
<path d="M9 16v-5.5a2.5 2.5 0 0 0 -5 0v5.5" />
</svg>
<SectionHeading>Handlers for every method</SectionHeading>
<p>
Define{" "}
<code class="bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono">
GET
</code>,{" "}
<code class="bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono">
POST
</code>,{" "}
<code class="bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono">
DELETE
</code>{" "}
— any HTTP method as a named handler on your route. Fresh maps
requests to the right function automatically, with full type safety.
</p>
<FancyLink href="/docs/concepts/routing" class="mt-2">
Learn about handlers
</FancyLink>
</div>
<div class="flex flex-col gap-4">
<CodeWindow name="routes/users/[id].tsx">
<CodeBlock code={apiCode} lang="js" />
</CodeWindow>
</div>
</SideBySide>
</PageSection>
);
}
2 changes: 1 addition & 1 deletion www/components/homepage/DemoBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function DemoBox(props: DemoBoxProps) {
const innerFlip = props.flip ? "skew-y-2 skew-x-3" : "-skew-y-2 -skew-x-3";
return (
<div
class={`bg-gradient-to-br font-medium from-blue-200 via-green-300 to-yellow-200 p-8 py-12 text-center items-center flex justify-center ${outerFlip}`}
class={`bg-gradient-to-br font-medium from-blue-200 via-green-300 to-yellow-200 p-5 py-8 text-center items-center flex justify-center text-sm ${outerFlip}`}
>
<div class={`w-full ${innerFlip}`}>
{props.children}
Expand Down
2 changes: 1 addition & 1 deletion www/components/homepage/ExampleArrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function ExampleArrow(
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"
class={`w-12 -my-8 relative z-10 mx-auto ${props?.class ?? ""}`}
class={`w-8 -my-6 relative z-10 mx-auto ${props?.class ?? ""}`}
>
<path
d="M50.704,18c46.89,80.967 38.288,189.344 5.941,254.255"
Expand Down
26 changes: 10 additions & 16 deletions www/components/homepage/FormsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { ExampleArrow } from "../homepage/ExampleArrow.tsx";
import { FancyLink } from "../FancyLink.tsx";
import { FormSubmitDemo } from "../../islands/FormSubmitDemo.tsx";

const routingCode = `import { define } from "../utils.ts";
const routingCode = `import { createDefine } from "fresh";
const define = createDefine();

export const handler = define.handlers({
async POST(ctx) {
const form = await ctx.req.formData();

// Do something with the form data here,
// then redirect user to thank you page
const treat = form.get("treat");
await db.votes.insert({ treat });

return new Response(null, {
status: 303,
Expand All @@ -34,8 +34,8 @@ export function FormsSection() {
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-route-square-2 text-fresh"
width="4rem"
height="4rem"
width="2.5rem"
height="2.5rem"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
Expand All @@ -49,17 +49,11 @@ export function FormsSection() {
<path d="M17 3h4v4h-4z" />
</svg>
</div>
<SectionHeading>
Forms, the right way
</SectionHeading>
<p>
Don't fight the browser. Fresh helps you handle form submissions and
other dynamic requests server-side, from any route.
</p>
<SectionHeading>Forms that just work</SectionHeading>
<p>
Since Fresh is built on{" "}
<a href="https://deno.com" class="underline">Deno</a>, it's built on
web standards.
Handle submissions server-side with standard Request and FormData.
No client-side state management, no serialization headaches.
Progressive enhancement comes free.
</p>
<FancyLink href="/docs/advanced/forms" class="mt-2">
Forms in Fresh
Expand Down
86 changes: 86 additions & 0 deletions www/components/homepage/HeadSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { CodeBlock } from "../../components/CodeBlock.tsx";
import { CodeWindow } from "../../components/CodeWindow.tsx";
import { PageSection } from "../../components/PageSection.tsx";
import { SideBySide } from "../../components/SideBySide.tsx";
import { SectionHeading } from "../../components/homepage/SectionHeading.tsx";
import { FancyLink } from "../../components/FancyLink.tsx";

const headCode = `import { Head } from "fresh/runtime";

export default function MyPage() {
return (
<>
<Head>
<title>My Page</title>
<meta name="description" content="..." />
<link rel="stylesheet" href="/styles.css" />
</Head>
<h1>Hello, world!</h1>
</>
);
}`;

export function HeadSection() {
return (
<PageSection>
<SideBySide
mdColSplit="3/2"
lgColSplit="3/2"
reverseOnDesktop
class="!items-start"
>
<div class="flex flex-col gap-4 md:sticky md:top-4">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-file-code text-fresh"
width="2.5rem"
height="2.5rem"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<title>Head element icon</title>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M14 3v4a1 1 0 0 0 1 1h4" />
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" />
<path d="M10 13l-1 2l1 2" />
<path d="M14 13l1 2l-1 2" />
</svg>
<SectionHeading>
Full control of{" "}
<span
// deno-lint-ignore react-no-danger
dangerouslySetInnerHTML={{ __html: "&lt;head&gt;" }}
/>
</SectionHeading>
<p>
Use the{" "}
<code
class="bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono"
// deno-lint-ignore react-no-danger
dangerouslySetInnerHTML={{ __html: "&lt;Head&gt;" }}
/>{" "}
component from any page or island to set titles, meta tags,
stylesheets, and scripts — no hoisting hacks or side channels
needed.
</p>
<FancyLink href="/docs/advanced/head" class="mt-2">
<span
// deno-lint-ignore react-no-danger
dangerouslySetInnerHTML={{ __html: "Learn about &lt;Head&gt;" }}
/>
</FancyLink>
</div>
<div class="flex flex-col gap-4">
<CodeWindow name="routes/my-page.tsx">
<CodeBlock code={headCode} lang="jsx" />
</CodeWindow>
</div>
</SideBySide>
</PageSection>
);
}
9 changes: 7 additions & 2 deletions www/components/homepage/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ export function Hero() {
<div class="bg-green-300 mt-0 pt-32 md:pt-48 !mb-0 bg-gradient-to-br from-blue-100 via-green-200 to-yellow-100">
<div class="md:grid grid-cols-5 gap-8 md:gap-16 items-center w-full max-w-screen-xl mx-auto px-4 md:px-8 lg:px-16 2xl:px-0">
<div class="flex-1 text-center md:text-left md:col-span-3 pb-8 md:pb-32">
<p class="italic text-gray-500 text-lg mb-4">Introducing Fresh:</p>
<h2 class="text-[calc(1rem+4vw)] leading-tight sm:text-5xl lg:text-6xl sm:tracking-tight sm:leading-none font-extrabold">
The simple, approachable, productive web framework
The framework so simple, you already know it.
</h2>
<p class="mt-6 text-lg sm:text-xl text-gray-700 text-balance max-w-prose">
No config files, no build step, no node_modules. Just one file and
you have a server with routing, JSX, and islands.
</p>
<div class="mt-12 flex flex-wrap justify-center items-stretch md:justify-start gap-4">
<FancyLink href="/docs/getting-started">Get started</FancyLink>
<CopyArea code={`deno run -Ar jsr:@fresh/init`} />
</div>
</div>
<div class="md:col-span-2 flex justify-center items-end">
<div class="md:col-span-2 flex justify-center items-end pb-8 md:pb-32">
<LemonTop />
</div>
</div>
Expand Down
18 changes: 10 additions & 8 deletions www/components/homepage/IslandsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export function IslandsSection() {
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-beach text-fresh"
width="4rem"
height="4rem"
width="2.5rem"
height="2.5rem"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
Expand All @@ -56,17 +56,19 @@ export function IslandsSection() {
<path d="M15 9l-3 5.196" />
<path d="M3 19.25a2.4 2.4 0 0 1 1 -.25a2.4 2.4 0 0 1 2 1a2.4 2.4 0 0 0 2 1a2.4 2.4 0 0 0 2 -1a2.4 2.4 0 0 1 2 -1a2.4 2.4 0 0 1 2 1a2.4 2.4 0 0 0 2 1a2.4 2.4 0 0 0 2 -1a2.4 2.4 0 0 1 2 -1a2.4 2.4 0 0 1 1 .25" />
</svg>
<SectionHeading>Island-based architecture</SectionHeading>
<SectionHeading>Interactive where it matters</SectionHeading>
<p>
Fresh ships plain HTML to the client, then hydrates with JavaScript
only where needed.
Most of your page is static HTML. Islands are the small, interactive
parts that get hydrated with JavaScript. You choose exactly what
runs on the client.
</p>
<p>
Because it's Preact, you get best-in-class performance, plus the
convenience of{" "}
Built on{" "}
<a href="https://preactjs.com/" class="underline">Preact</a> and
{" "}
<a href="https://preactjs.com/guide/v10/signals/" class="underline">
Signals
</a>.
</a>, so islands are tiny and reactive out of the box.
</p>
<FancyLink href="/docs/concepts/islands" class="mt-2">
Learn more about islands
Expand Down
Loading