mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
added minimal astro adapter + improved the example
This commit is contained in:
@@ -179,3 +179,8 @@ await tsup.build({
|
|||||||
platform: "node",
|
platform: "node",
|
||||||
format: ["esm", "cjs"]
|
format: ["esm", "cjs"]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await tsup.build({
|
||||||
|
...baseConfig("astro"),
|
||||||
|
format: ["esm", "cjs"]
|
||||||
|
});
|
||||||
|
|||||||
@@ -160,6 +160,11 @@
|
|||||||
"import": "./dist/adapter/node/index.js",
|
"import": "./dist/adapter/node/index.js",
|
||||||
"require": "./dist/adapter/node/index.cjs"
|
"require": "./dist/adapter/node/index.cjs"
|
||||||
},
|
},
|
||||||
|
"./adapter/astro": {
|
||||||
|
"types": "./dist/adapter/astro/index.d.ts",
|
||||||
|
"import": "./dist/adapter/astro/index.js",
|
||||||
|
"require": "./dist/adapter/astro/index.cjs"
|
||||||
|
},
|
||||||
"./dist/styles.css": "./dist/ui/main.css",
|
"./dist/styles.css": "./dist/ui/main.css",
|
||||||
"./dist/manifest.json": "./dist/static/manifest.json"
|
"./dist/manifest.json": "./dist/static/manifest.json"
|
||||||
},
|
},
|
||||||
|
|||||||
21
app/src/adapter/astro/astro.adapter.ts
Normal file
21
app/src/adapter/astro/astro.adapter.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Api, type ApiOptions } from "bknd";
|
||||||
|
|
||||||
|
type TAstro = {
|
||||||
|
request: {
|
||||||
|
url: string;
|
||||||
|
headers: Headers;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Options = {
|
||||||
|
mode?: "static" | "dynamic";
|
||||||
|
} & Omit<ApiOptions, "host"> & {
|
||||||
|
host?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getApi(Astro: TAstro, options: Options = { mode: "static" }) {
|
||||||
|
return new Api({
|
||||||
|
host: new URL(Astro.request.url).origin,
|
||||||
|
headers: options.mode === "dynamic" ? Astro.request.headers : undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
1
app/src/adapter/astro/index.ts
Normal file
1
app/src/adapter/astro/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./astro.adapter";
|
||||||
@@ -135,10 +135,10 @@ type FormInputElement = HTMLInputElement | HTMLTextAreaElement;
|
|||||||
function EntityFormField({ fieldApi, field, action, data, ...props }: EntityFormFieldProps) {
|
function EntityFormField({ fieldApi, field, action, data, ...props }: EntityFormFieldProps) {
|
||||||
const handleUpdate = useEvent((e: React.ChangeEvent<FormInputElement> | any) => {
|
const handleUpdate = useEvent((e: React.ChangeEvent<FormInputElement> | any) => {
|
||||||
if (typeof e === "object" && "target" in e) {
|
if (typeof e === "object" && "target" in e) {
|
||||||
console.log("handleUpdate", e.target.value);
|
//console.log("handleUpdate", e.target.value);
|
||||||
fieldApi.handleChange(e.target.value);
|
fieldApi.handleChange(e.target.value);
|
||||||
} else {
|
} else {
|
||||||
console.log("handleUpdate-", e);
|
//console.log("handleUpdate-", e);
|
||||||
fieldApi.handleChange(e);
|
fieldApi.handleChange(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
73
examples/astro/src/components/Card.astro
Normal file
73
examples/astro/src/components/Card.astro
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
done?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { done, title, body } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<li class="link-card" data-done={done ? 1 : undefined}>
|
||||||
|
<div class="inner">
|
||||||
|
<div class="check">
|
||||||
|
<span>{done ? "✅" : "🔘"}</span>
|
||||||
|
</div>
|
||||||
|
<h2>
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
{body}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<style>
|
||||||
|
.link-card {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
padding: 1px;
|
||||||
|
background-color: #23262d;
|
||||||
|
background-image: none;
|
||||||
|
background-size: 400%;
|
||||||
|
border-radius: 7px;
|
||||||
|
background-position: 100%;
|
||||||
|
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
.link-card[data-done] {
|
||||||
|
background-color: #0c3e29;
|
||||||
|
}
|
||||||
|
.link-card > .inner {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
text-decoration: none;
|
||||||
|
line-height: 1.4;
|
||||||
|
padding: calc(1.5rem - 1px);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
background-color: #23262d;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.inner .check {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.75rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.link-card:is(:hover, :focus-within) {
|
||||||
|
background-position: 0;
|
||||||
|
background-image: var(--accent-gradient);
|
||||||
|
}
|
||||||
|
.link-card:is(:hover, :focus-within) h2 {
|
||||||
|
color: rgb(var(--accent-light));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
137
examples/astro/src/layouts/Layout.astro
Normal file
137
examples/astro/src/layouts/Layout.astro
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
---
|
||||||
|
import Card from "../components/Card.astro";
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title } = Astro.props;
|
||||||
|
const path = new URL(Astro.request.url).pathname;
|
||||||
|
const items = [
|
||||||
|
{ href: "/", text: "Home (static)" },
|
||||||
|
{ href: "/ssr", text: "SSR (with auth)" },
|
||||||
|
{ href: "/admin", text: "Admin" }
|
||||||
|
];
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="description" content="Astro description" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
<title>{title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
{items.map((item) => (
|
||||||
|
<a href={item.href} data-active={path === item.href}>{item.text}</a>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<div class="center">
|
||||||
|
<h1>bknd + <span class="text-gradient">Astro</span></h1>
|
||||||
|
<slot name="context" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<style is:global>
|
||||||
|
:root {
|
||||||
|
--accent: 136, 58, 234;
|
||||||
|
--accent-light: 224, 204, 250;
|
||||||
|
--accent-dark: 49, 10, 101;
|
||||||
|
--accent-gradient: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
rgb(var(--accent)),
|
||||||
|
rgb(var(--accent-light)) 30%,
|
||||||
|
white 60%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
background: #13151a;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-family:
|
||||||
|
Menlo,
|
||||||
|
Monaco,
|
||||||
|
Lucida Console,
|
||||||
|
Liberation Mono,
|
||||||
|
DejaVu Sans Mono,
|
||||||
|
Bitstream Vera Sans Mono,
|
||||||
|
Courier New,
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
a, a:visited {
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
width: 800px;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
nav a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
nav a[data-active],
|
||||||
|
nav a:hover {
|
||||||
|
background-image: var(--accent-gradient);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-size: 400%;
|
||||||
|
background-position: 0%;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
width: 800px;
|
||||||
|
max-width: calc(100% - 2rem);
|
||||||
|
color: white;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
main .center {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
p {
|
||||||
|
opacity: 50%;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.astro-a {
|
||||||
|
position: absolute;
|
||||||
|
top: -32px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translatex(-50%);
|
||||||
|
width: 220px;
|
||||||
|
height: auto;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.4em;
|
||||||
|
}
|
||||||
|
.text-gradient {
|
||||||
|
background-image: var(--accent-gradient);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-size: 400%;
|
||||||
|
background-position: 0%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
---
|
---
|
||||||
import { Api } from "bknd";
|
|
||||||
import { Admin } from "bknd/ui";
|
import { Admin } from "bknd/ui";
|
||||||
import "bknd/dist/styles.css";
|
import "bknd/dist/styles.css";
|
||||||
|
|
||||||
export const prerender = false;
|
import { getApi } from "bknd/adapter/astro";
|
||||||
const api = new Api({
|
|
||||||
host: new URL(Astro.request.url).origin,
|
const api = getApi(Astro, { mode: "dynamic" });
|
||||||
headers: Astro.request.headers
|
|
||||||
});
|
|
||||||
const user = api.getUser();
|
const user = api.getUser();
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<Admin
|
<Admin
|
||||||
withProvider={{ user }}
|
withProvider={{ user }}
|
||||||
config={{ basepath: "/admin" }}
|
config={{ basepath: "/admin", color_scheme: "dark" }}
|
||||||
client:load
|
client:load
|
||||||
/>
|
/>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,16 +1,29 @@
|
|||||||
---
|
---
|
||||||
import { Api } from "bknd";
|
import { getApi } from "bknd/adapter/astro";
|
||||||
const api = new Api({
|
import Card from "../components/Card.astro";
|
||||||
host: new URL(Astro.request.url).origin
|
import Layout from "../layouts/Layout.astro";
|
||||||
});
|
const api = getApi(Astro);
|
||||||
const { data } = await api.data.readMany("todos");
|
const { data } = await api.data.readMany("todos");
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<Layout title="Welcome to Astro.">
|
||||||
|
<p slot="context">Static Rendering</p>
|
||||||
|
<ul role="list" class="link-card-grid">
|
||||||
|
{data.map((todo: any) => (
|
||||||
|
<Card
|
||||||
|
done={todo.done}
|
||||||
|
title={todo.title}
|
||||||
|
body={todo.description}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
<h1>Home (static)</h1>
|
<style>
|
||||||
<h2>Data</h2>
|
.link-card-grid {
|
||||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
||||||
<a href="/admin">Admin</a> -
|
gap: 2rem;
|
||||||
<a href="/ssr">SSR (with auth)</a> -
|
padding: 0;
|
||||||
<a href="/">Home (static)</a>
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,23 +1,35 @@
|
|||||||
---
|
---
|
||||||
import { Api } from "bknd";
|
import { getApi } from "bknd/adapter/astro";
|
||||||
const api = new Api({
|
import Card from "../components/Card.astro";
|
||||||
host: new URL(Astro.request.url).origin,
|
import Layout from "../layouts/Layout.astro";
|
||||||
headers: Astro.request.headers
|
const api = getApi(Astro, { mode: "dynamic" });
|
||||||
});
|
|
||||||
const { data } = await api.data.readMany("todos");
|
const { data } = await api.data.readMany("todos");
|
||||||
const user = api.getUser();
|
const user = api.getUser();
|
||||||
console.log("user", user);
|
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
---
|
---
|
||||||
|
|
||||||
<h1>SSR</h1>
|
<Layout title="Welcome to Astro.">
|
||||||
<h2>Data</h1>
|
<p slot="context">Server Side Rendering</p>
|
||||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
<ul role="list" class="link-card-grid">
|
||||||
|
{data.map((todo: any) => (
|
||||||
|
<Card
|
||||||
|
done={todo.done}
|
||||||
|
title={todo.title}
|
||||||
|
body={todo.description}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div class="center">
|
||||||
|
{user ? <p>Logged in as <b>{user?.email}</b>. <a href="/api/auth/logout">Logout</a></p> : <p>Not authenticated. <a href="/admin/auth/login">Sign in</a></p>}
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
<h2>User</h1>
|
<style>
|
||||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
.link-card-grid {
|
||||||
|
display: grid;
|
||||||
<a href="/admin">Admin</a> -
|
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
||||||
<a href="/ssr">SSR (with auth)</a> -
|
gap: 2rem;
|
||||||
<a href="/">Home (static)</a>
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user