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(example): add SSR dialog control example #683

Merged
merged 3 commits into from
Dec 15, 2024
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
4 changes: 4 additions & 0 deletions examples/with-ssr-modal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build
node_modules
out
.vercel
7 changes: 7 additions & 0 deletions examples/with-ssr-modal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# with-ssr-modal

Example controlling the open/close rendering of a modal with server code only (server action + SSR with streaming).

```bash
bun create brisa --example with-ssr-modal
```
2 changes: 2 additions & 0 deletions examples/with-ssr-modal/bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[test]
preload = "brisa/test"
20 changes: 20 additions & 0 deletions examples/with-ssr-modal/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "with-ssr-modal",
"module": "src/pages/index.tsx",
"type": "module",
"example-category": "basics",
"webTitle": "Server-Side Dialog Management",
"scripts": {
"dev": "brisa dev",
"dev:debug": "brisa dev --debug",
"build": "brisa build",
"start": "brisa start"
},
"dependencies": {
"brisa": "0.2.1-canary.2"
},
"devDependencies": {
"@types/bun": "latest",
"typescript": "latest"
}
}
19 changes: 19 additions & 0 deletions examples/with-ssr-modal/src/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default function Footer() {
return (
<footer>
<p>
View on{' '}
<a
class="CTA"
href="https://github.com/brisa-build/brisa"
id="github-link"
target="_blank"
data-replace="GitHub"
rel="noreferrer"
>
<span>GitHub</span>
</a>
</p>
</footer>
);
}
25 changes: 25 additions & 0 deletions examples/with-ssr-modal/src/components/navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export default function Nav() {
return (
<nav>
<div class="nav-content">
<a
class="logo"
href="https://brisa.build"
target="_blank"
rel="noreferrer"
>
<img src="/brisa.svg" alt="Brisa Framework logo" width="30" />
Brisa
</a>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/about">About Brisa</a>
</li>
</ul>
</div>
</nav>
);
}
36 changes: 36 additions & 0 deletions examples/with-ssr-modal/src/layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Nav from '@/components/navigation';
import Footer from '@/components/footer';

import '@/styles/style.css';
import '@/styles/nav.css';
import '@/styles/footer.css';

export default function Layout({ children }: { children: JSX.Element }) {
return (
<html lang="en">
<head>
<title id="title">Brisa</title>
<meta name="theme-color" content="#ad1457" />
<link rel="shortcut icon" href="/brisa.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossorigin="true"
/>
<link
href="https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap"
rel="stylesheet"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<header>
<Nav />
</header>
<main>{children}</main>
<Footer />
</body>
</html>
);
}
119 changes: 119 additions & 0 deletions examples/with-ssr-modal/src/pages/about/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
export function Head() {
return <title id="title">About Brisa</title>;
}

export default function About() {
return (
<>
<div class="hero">
<h1>
<span class="h1_addition">About </span>Brisa
</h1>
<p class="edit-note">✏️ Change this page on </p>
<code>src/pages/about/index.tsx</code>
</div>
<div class="about-sections">
<section>
<h2>Curious for more details? Let's dive in!</h2>

<p>
Brisa is the Web Platform Framework. Its pages are dynamically
server-rendered JSX components, so there's zero JavaScript shipped
to the browser by default.
</p>

<p>
Everything runs exclusively on the server by default, except the Web
Components folder which, of course, also runs on the client.
</p>

<p>
We have solved the burden of writing and processing Web Components.
Easy to write with Signals, Server-Side rendering, and optimized in
build time to be fast and small; if you use Web Components, it adds
+3KB.
</p>

<p>
You can also use the Brisa compiler to create libraries of Web
Components that work in any framework- or even without a framework,
and they are supported by Server-Side rendering.
</p>

<p>
We have also solved the Server Actions. With Brisa, the server
components can capture any browser event: onSubmit, onInput,
onFocus, onClick, and, all events from Web Components, like
onClickOnMyComponent. These are all Server-Actions now, so you don't
need to put "use client" nor "use server" any more. On the server
they are simply Server-Actions, and on the client they are simply
browser-events.
</p>

<p>
To make this possible we have improved the communication between
both worlds, creating new concepts like "Action Signals". With
these, the server can react to Web Components without the need for
rerenders. We have also added ideas from HTMX; you have extra
attributes in the HTML for debouncing or managing errors and pending
states.
</p>

<p>Brisa not only uses Hypermedia, it streams it over the wire.</p>

<p>
Brisa is also the only framework with full Internationalization
support. not only routing, but you can also translate your pages and
the URL pathnames if you need it. If you use i18n, the server
components are 0 Bytes, but in Web Components are 800 B. At the end
we use the Web Platform; we make a bridge with the ECMAScript Intl
API to make it easier for you to translate your Web Components.
</p>

<p>
In Brisa we like the idea that all the tooling is integrated, that's
why Brisa is made with Bun we have extended the Matchers and added
an API so you can run with Bun the tests of your Components.
</p>

<p>
Bun is great and improves the development experience a lot. Although
we recommend Bun.js also as runtime, as output you can use Node.js
or Deno if you want, generate a static output and upload it to a
CDN, or generate an executable app for Android (.apk),  iOS (.ipa), 
Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is
multiplatform thanks to its integration with Tauri.
</p>

<p>
We support Partial Prerendering, you can prerender only a part of
your page, such as the footer.
</p>

<p>
We also support many more features like middleware, layouts,
WebSockets, API routes, suspense, etc.
</p>

<p>
Brisa is the future of the Web, and the future is now. We invite you
to try it and contribute to the community.
</p>

<p class="CTA-text">
Ready to start?{' '}
<a
class="CTA"
href="https://brisa.build"
target="_blank"
data-replace="Read the docs"
rel="noreferrer"
>
<span>Read the docs</span>
</a>
</p>
</section>
</div>
</>
);
}
81 changes: 81 additions & 0 deletions examples/with-ssr-modal/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { renderComponent } from 'brisa/server';

type Question = {
answer: string;
question: string;
id: number;
};

// All this code is server-code. So is impossible that the user knows the answer
// after inspecting the page.
const questions: Question[] = [
{ id: 1, answer: 'no', question: 'Is the Earth flat? ' },
{ id: 2, answer: 'yes', question: 'Is the Earth round? ' },
{ id: 3, answer: 'no', question: 'Can giraffes lay eggs?' },
{ id: 4, answer: 'yes', question: 'Can penguins fly?' },
{ id: 5, answer: 'no', question: 'Can a cow jump over the moon?' },
{ id: 6, answer: 'yes', question: 'Is water wet by definition?' },
{ id: 7, answer: 'yes', question: 'Is the sky blue?' },
{ id: 8, answer: 'yes', question: 'Do fish sleep with their eyes open?' },
{ id: 9, answer: 'no', question: 'Can a cow fly?' },
];

function openModal() {
const randomIndex = Math.floor(Math.random() * questions.length);
renderComponent({
element: <Modal {...questions[randomIndex]} />,
target: '#content',
});
}

function processAnswer(e: ClickEvent, value = 'yes') {
const id = (e.target as HTMLButtonElement).dataset.id;
const isCorrect = questions.find((q) => q.id === Number(id)).answer === value;
renderComponent({
element: isCorrect ? (
<p id="content" class="correct">
Correct!
</p>
) : (
<p id="content" class="incorrect">
Incorrect!
</p>
),
target: 'dialog',
});
}

export default function Homepage() {
return (
<>
<div class="hero">
<h1>
<span class="h1_addition">Welcome to </span>Brisa
</h1>
<p class="edit-note">✏️ SSR Modal example</p>
<code>src/pages/index.tsx</code>
</div>

<form onSubmit={openModal}>
<button>Open modal</button>
<div id="content" />
</form>
</>
);
}

function Modal({ question, answer, id }: Question) {
return (
<dialog open>
<form method="dialog">
<h2>{question}</h2>
<button data-id={id} onClick={(e) => processAnswer(e, 'yes')}>
Yes
</button>
<button data-id={id} onClick={(e) => processAnswer(e, 'no')}>
No
</button>
</form>
</dialog>
);
}
10 changes: 10 additions & 0 deletions examples/with-ssr-modal/src/public/brisa.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions examples/with-ssr-modal/src/styles/footer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
footer {
display: grid;
font-family: "Poppins", sans-serif;
font-size: 27px;
line-height: 1.5;
height: 15vh;
place-items: center;
}
46 changes: 46 additions & 0 deletions examples/with-ssr-modal/src/styles/nav.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Navigation Styles */
nav {
background-image: linear-gradient(to right, rgb(69 177 228), rgb(4 14 113));
position: fixed;
color: #fff;
padding: 1rem 2rem;
width: 100vw;
box-shadow: 2px 2px 10px 0 hsla(0, 0%, 40%, 0.5);
}

.nav-content {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 800px;
margin: auto;
}

nav .logo {
font-size: 1.5rem;
font-weight: bold;
display: flex;
gap: 10px;
text-decoration: none;
color: #fff;
}

nav ul {
list-style: none;
display: flex;
}

nav ul li {
margin: 0 1rem;
}

nav ul li a {
color: #fff;
text-decoration: none;
font-size: 1rem;
transition: color 0.3s;
}

nav ul li a:hover {
color: #f39c12;
}
Loading
Loading