From fd28915e1b415cf2dc68d983d0595b355a639f35 Mon Sep 17 00:00:00 2001
From: Aral Roca
Date: Sun, 15 Dec 2024 21:39:00 +0100
Subject: [PATCH 1/3] feat(example): add SSR dialog control example
---
examples/with-ssr-modal/.gitignore | 4 +
examples/with-ssr-modal/README.md | 7 +
examples/with-ssr-modal/bunfig.toml | 2 +
examples/with-ssr-modal/package.json | 19 ++
.../with-ssr-modal/src/components/footer.tsx | 19 ++
.../src/components/navigation.tsx | 25 ++
examples/with-ssr-modal/src/layout/index.tsx | 36 +++
.../with-ssr-modal/src/pages/about/index.tsx | 119 ++++++++
examples/with-ssr-modal/src/pages/index.tsx | 79 ++++++
examples/with-ssr-modal/src/public/brisa.svg | 10 +
examples/with-ssr-modal/src/styles/footer.css | 8 +
examples/with-ssr-modal/src/styles/nav.css | 46 +++
examples/with-ssr-modal/src/styles/style.css | 266 ++++++++++++++++++
examples/with-ssr-modal/tsconfig.json | 27 ++
14 files changed, 667 insertions(+)
create mode 100644 examples/with-ssr-modal/.gitignore
create mode 100644 examples/with-ssr-modal/README.md
create mode 100644 examples/with-ssr-modal/bunfig.toml
create mode 100644 examples/with-ssr-modal/package.json
create mode 100644 examples/with-ssr-modal/src/components/footer.tsx
create mode 100644 examples/with-ssr-modal/src/components/navigation.tsx
create mode 100644 examples/with-ssr-modal/src/layout/index.tsx
create mode 100644 examples/with-ssr-modal/src/pages/about/index.tsx
create mode 100644 examples/with-ssr-modal/src/pages/index.tsx
create mode 100644 examples/with-ssr-modal/src/public/brisa.svg
create mode 100644 examples/with-ssr-modal/src/styles/footer.css
create mode 100644 examples/with-ssr-modal/src/styles/nav.css
create mode 100644 examples/with-ssr-modal/src/styles/style.css
create mode 100644 examples/with-ssr-modal/tsconfig.json
diff --git a/examples/with-ssr-modal/.gitignore b/examples/with-ssr-modal/.gitignore
new file mode 100644
index 000000000..6680baa7b
--- /dev/null
+++ b/examples/with-ssr-modal/.gitignore
@@ -0,0 +1,4 @@
+build
+node_modules
+out
+.vercel
diff --git a/examples/with-ssr-modal/README.md b/examples/with-ssr-modal/README.md
new file mode 100644
index 000000000..59042885e
--- /dev/null
+++ b/examples/with-ssr-modal/README.md
@@ -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
+```
diff --git a/examples/with-ssr-modal/bunfig.toml b/examples/with-ssr-modal/bunfig.toml
new file mode 100644
index 000000000..69803a7a9
--- /dev/null
+++ b/examples/with-ssr-modal/bunfig.toml
@@ -0,0 +1,2 @@
+[test]
+preload = "brisa/test"
\ No newline at end of file
diff --git a/examples/with-ssr-modal/package.json b/examples/with-ssr-modal/package.json
new file mode 100644
index 000000000..b35bd66ac
--- /dev/null
+++ b/examples/with-ssr-modal/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "with-ssr-modal",
+ "module": "src/pages/index.tsx",
+ "type": "module",
+ "example-category": "basics",
+ "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"
+ }
+}
diff --git a/examples/with-ssr-modal/src/components/footer.tsx b/examples/with-ssr-modal/src/components/footer.tsx
new file mode 100644
index 000000000..d61deb5f8
--- /dev/null
+++ b/examples/with-ssr-modal/src/components/footer.tsx
@@ -0,0 +1,19 @@
+export default function Footer() {
+ return (
+
+ );
+}
diff --git a/examples/with-ssr-modal/src/components/navigation.tsx b/examples/with-ssr-modal/src/components/navigation.tsx
new file mode 100644
index 000000000..eb11e0eb8
--- /dev/null
+++ b/examples/with-ssr-modal/src/components/navigation.tsx
@@ -0,0 +1,25 @@
+export default function Nav() {
+ return (
+
+
+
+ );
+}
diff --git a/examples/with-ssr-modal/src/layout/index.tsx b/examples/with-ssr-modal/src/layout/index.tsx
new file mode 100644
index 000000000..65a4edb6c
--- /dev/null
+++ b/examples/with-ssr-modal/src/layout/index.tsx
@@ -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 (
+
+
+ Brisa
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/examples/with-ssr-modal/src/pages/about/index.tsx b/examples/with-ssr-modal/src/pages/about/index.tsx
new file mode 100644
index 000000000..d20342d7c
--- /dev/null
+++ b/examples/with-ssr-modal/src/pages/about/index.tsx
@@ -0,0 +1,119 @@
+export function Head() {
+ return About Brisa ;
+}
+
+export default function About() {
+ return (
+ <>
+
+
+ About Brisa
+
+
✏️ Change this page on
+
src/pages/about/index.tsx
+
+
+
+ Curious for more details? Let's dive in!
+
+
+ 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.
+
+
+
+ Everything runs exclusively on the server by default, except the Web
+ Components folder which, of course, also runs on the client.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+ Brisa not only uses Hypermedia, it streams it over the wire.
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ We support Partial Prerendering, you can prerender only a part of
+ your page, such as the footer.
+
+
+
+ We also support many more features like middleware, layouts,
+ WebSockets, API routes, suspense, etc.
+
+
+
+ Brisa is the future of the Web, and the future is now. We invite you
+ to try it and contribute to the community.
+
+
+
+ Ready to start?{' '}
+
+ Read the docs
+
+
+
+
+ >
+ );
+}
diff --git a/examples/with-ssr-modal/src/pages/index.tsx b/examples/with-ssr-modal/src/pages/index.tsx
new file mode 100644
index 000000000..ba7945985
--- /dev/null
+++ b/examples/with-ssr-modal/src/pages/index.tsx
@@ -0,0 +1,79 @@
+import { renderComponent } from "brisa/server";
+
+type Question = {
+ answer: string;
+ question: string;
+ id: number;
+};
+
+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: ,
+ 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 ? (
+
+ Correct!
+
+ ) : (
+
+ Incorrect!
+
+ ),
+ target: "dialog",
+ });
+}
+
+export default function Homepage() {
+ return (
+ <>
+
+
+ Welcome to Brisa
+
+
✏️ SSR Modal example
+
src/pages/index.tsx
+
+
+
+ >
+ );
+}
+
+function Modal({ question, answer, id }: Question) {
+ return (
+
+
+
+ );
+}
diff --git a/examples/with-ssr-modal/src/public/brisa.svg b/examples/with-ssr-modal/src/public/brisa.svg
new file mode 100644
index 000000000..02010e7d2
--- /dev/null
+++ b/examples/with-ssr-modal/src/public/brisa.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/with-ssr-modal/src/styles/footer.css b/examples/with-ssr-modal/src/styles/footer.css
new file mode 100644
index 000000000..72bb5e61a
--- /dev/null
+++ b/examples/with-ssr-modal/src/styles/footer.css
@@ -0,0 +1,8 @@
+footer {
+ display: grid;
+ font-family: "Poppins", sans-serif;
+ font-size: 27px;
+ line-height: 1.5;
+ height: 15vh;
+ place-items: center;
+}
diff --git a/examples/with-ssr-modal/src/styles/nav.css b/examples/with-ssr-modal/src/styles/nav.css
new file mode 100644
index 000000000..b2054d068
--- /dev/null
+++ b/examples/with-ssr-modal/src/styles/nav.css
@@ -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;
+}
diff --git a/examples/with-ssr-modal/src/styles/style.css b/examples/with-ssr-modal/src/styles/style.css
new file mode 100644
index 000000000..09a4d9edc
--- /dev/null
+++ b/examples/with-ssr-modal/src/styles/style.css
@@ -0,0 +1,266 @@
+/* General Styles */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
+}
+
+body {
+ color: #333;
+ line-height: 1.6;
+ text-align: center;
+}
+
+/* Hero Section */
+.hero {
+ background: linear-gradient(
+ 90deg,
+ rgba(255, 255, 255, 1) 0%,
+ rgba(240, 240, 255, 1) 26%,
+ rgba(149, 237, 255, 1) 100%
+ );
+ background-attachment: fixed;
+ padding: 6rem 2rem 2rem;
+}
+
+.hero h1 {
+ font-size: 3rem;
+ line-height: 1.25;
+ font-weight: 700;
+ background-clip: text;
+ background-image: linear-gradient(
+ 120deg,
+ rgb(44, 235, 207) 30%,
+ rgb(44, 197, 226)
+ );
+ color: rgba(0, 0, 0, 0);
+
+ .h1_addition {
+ line-height: 1;
+ font-weight: 700;
+ background-clip: text;
+ margin: 0px;
+ background-image: linear-gradient(
+ to right,
+ rgb(69, 177, 228),
+ rgb(96, 108, 226)
+ );
+ color: rgba(0, 0, 0, 0);
+ }
+}
+
+li {
+ list-style: none;
+}
+
+.hero p {
+ font-size: 1.25rem;
+}
+
+/* Counter Section */
+.counter {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+}
+.counter-section {
+ padding: 3rem 2rem;
+ background-color: #fff;
+}
+
+.counter-section h2 {
+ font-size: 2rem;
+ margin-bottom: 2rem;
+}
+
+.example {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+}
+
+/* About Section */
+.about-section {
+ padding: 3rem 2rem;
+}
+
+.about-section h2 {
+ font-size: 2rem;
+ margin-bottom: 1rem;
+}
+
+.about-section p {
+ font-size: 1.125rem;
+ color: #666;
+}
+
+.about-sections {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 1rem;
+ width: 90%;
+ max-width: 800px;
+ margin: auto;
+ h2 {
+ font-size: 1.5rem;
+ margin-bottom: 1rem;
+ color: #333;
+ text-align: center;
+ }
+ summary {
+ text-align: left;
+ color: #2c3e50;
+ margin: 2rem auto;
+ max-width: 600px;
+ font-size: 0.9rem;
+ }
+
+ section {
+ padding: 1rem;
+ margin: 20px auto;
+ max-width: 800px;
+ text-align: left;
+ text-wrap: pretty;
+
+ p {
+ margin: 1rem auto;
+ }
+ }
+}
+
+.edit-note {
+ margin-top: 10px;
+ font-family: "Permanent Marker", cursive;
+ color: #2c3e50;
+ font-size: 0.9rem;
+}
+
+code {
+ background: #ffeff0;
+ word-wrap: break-word;
+ box-decoration-break: clone;
+ padding: .1rem .3rem .2rem;
+ border-radius: .2rem;
+}
+
+.CTA {
+ overflow: hidden;
+ position: relative;
+ display: inline-block;
+ text-decoration: none;
+ color: #18272f;
+ font-weight: 700;
+ vertical-align: top;
+}
+
+.CTA::before,
+.CTA::after {
+ content: "";
+ position: absolute;
+ width: 100%;
+ left: 0;
+}
+
+.CTA::before {
+ background-clip: text;
+ background-image: linear-gradient(
+ 120deg,
+ rgb(44, 235, 207) 30%,
+ rgb(44, 197, 226)
+ );
+ color: rgba(0, 0, 0, 0);
+ height: 2px;
+ bottom: 0;
+ transform-origin: 100% 50%;
+ transform: scaleX(0);
+ transition: transform .3s cubic-bezier(0.76, 0, 0.24, 1);
+}
+
+.CTA::after {
+ content: attr(data-replace);
+ height: 100%;
+ top: 0;
+ transform-origin: 100% 50%;
+ transform: translate3d(200%, 0, 0);
+ transition: transform .3s cubic-bezier(0.76, 0, 0.24, 1);
+ background-clip: text;
+ background-image: linear-gradient(
+ 120deg,
+ rgb(44, 235, 207) 30%,
+ rgb(44, 197, 226)
+ );
+ color: rgba(0, 0, 0, 0);
+}
+
+.CTA:hover::before {
+ transform-origin: 0% 50%;
+ transform: scaleX(1);
+}
+
+.CTA:hover::after {
+ transform: translate3d(0, 0, 0);
+}
+
+.CTA span {
+ display: inline-block;
+ transition: transform .3s cubic-bezier(0.76, 0, 0.24, 1);
+}
+.CTA:hover span {
+ transform: translate3d(-200%, 0, 0);
+}
+.CTA-text {
+ display: inline-block;
+ position: relative;
+ padding: 0 1rem;
+ font-size: 1.2rem;
+ text-align: center;
+ width: 100%;
+ margin: 2rem auto;
+}
+
+form button {
+ background: #2c3e50;
+ color: #fff;
+ border: none;
+ padding: 0.5rem 1rem;
+ cursor: pointer;
+ font-size: 1rem;
+ margin: 1rem 10px;
+}
+
+dialog {
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ padding: 50px;
+ z-index: 1000;
+ top: 200px;
+ margin: auto;
+ background: #fff;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+
+ &::backdrop {
+ background: rgba(0, 0, 0, 0.5);
+ }
+}
+
+.correct {
+ color: green;
+ animation: fadeIn 0.5s ease;
+}
+
+.incorrect {
+ color: red;
+ animation: fadeIn 0.5s ease;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
diff --git a/examples/with-ssr-modal/tsconfig.json b/examples/with-ssr-modal/tsconfig.json
new file mode 100644
index 000000000..b33db57da
--- /dev/null
+++ b/examples/with-ssr-modal/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./src",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "module": "esnext",
+ "target": "esnext",
+ "moduleResolution": "bundler",
+ "moduleDetection": "force",
+ "allowImportingTsExtensions": true,
+ "noEmit": true,
+ "composite": true,
+ "strict": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "jsx": "react-jsx",
+ "jsxImportSource": "brisa",
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "verbatimModuleSyntax": true,
+ "noFallthroughCasesInSwitch": true,
+ "types": ["brisa"],
+ "paths": {
+ "@/*": ["*"]
+ }
+ }
+}
From 9d8d2f8abce05531f3c7f00644b875a8c02ae246 Mon Sep 17 00:00:00 2001
From: Aral Roca
Date: Sun, 15 Dec 2024 21:39:36 +0100
Subject: [PATCH 2/3] reformat
---
examples/with-ssr-modal/src/pages/index.tsx | 30 ++++++++++-----------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/examples/with-ssr-modal/src/pages/index.tsx b/examples/with-ssr-modal/src/pages/index.tsx
index ba7945985..19fc9fdfc 100644
--- a/examples/with-ssr-modal/src/pages/index.tsx
+++ b/examples/with-ssr-modal/src/pages/index.tsx
@@ -1,4 +1,4 @@
-import { renderComponent } from "brisa/server";
+import { renderComponent } from 'brisa/server';
type Question = {
answer: string;
@@ -7,26 +7,26 @@ type Question = {
};
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?" },
+ { 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: ,
- target: "#content",
+ target: '#content',
});
}
-function processAnswer(e: ClickEvent, value = "yes") {
+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({
@@ -39,7 +39,7 @@ function processAnswer(e: ClickEvent, value = "yes") {
Incorrect!
),
- target: "dialog",
+ target: 'dialog',
});
}
@@ -67,10 +67,10 @@ function Modal({ question, answer, id }: Question) {
From 4fa749df072955da5213001ef72e11fe63959ff0 Mon Sep 17 00:00:00 2001
From: Aral Roca
Date: Sun, 15 Dec 2024 23:27:15 +0100
Subject: [PATCH 3/3] docs: update package + comment
---
examples/with-ssr-modal/package.json | 1 +
examples/with-ssr-modal/src/pages/index.tsx | 2 ++
2 files changed, 3 insertions(+)
diff --git a/examples/with-ssr-modal/package.json b/examples/with-ssr-modal/package.json
index b35bd66ac..7dc39ed3b 100644
--- a/examples/with-ssr-modal/package.json
+++ b/examples/with-ssr-modal/package.json
@@ -3,6 +3,7 @@
"module": "src/pages/index.tsx",
"type": "module",
"example-category": "basics",
+ "webTitle": "Server-Side Dialog Management",
"scripts": {
"dev": "brisa dev",
"dev:debug": "brisa dev --debug",
diff --git a/examples/with-ssr-modal/src/pages/index.tsx b/examples/with-ssr-modal/src/pages/index.tsx
index 19fc9fdfc..86fec668c 100644
--- a/examples/with-ssr-modal/src/pages/index.tsx
+++ b/examples/with-ssr-modal/src/pages/index.tsx
@@ -6,6 +6,8 @@ type Question = {
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? ' },