mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
added minimal astro adapter + improved the example
This commit is contained in:
@@ -179,3 +179,8 @@ await tsup.build({
|
||||
platform: "node",
|
||||
format: ["esm", "cjs"]
|
||||
});
|
||||
|
||||
await tsup.build({
|
||||
...baseConfig("astro"),
|
||||
format: ["esm", "cjs"]
|
||||
});
|
||||
|
||||
@@ -160,6 +160,11 @@
|
||||
"import": "./dist/adapter/node/index.js",
|
||||
"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/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) {
|
||||
const handleUpdate = useEvent((e: React.ChangeEvent<FormInputElement> | any) => {
|
||||
if (typeof e === "object" && "target" in e) {
|
||||
console.log("handleUpdate", e.target.value);
|
||||
//console.log("handleUpdate", e.target.value);
|
||||
fieldApi.handleChange(e.target.value);
|
||||
} else {
|
||||
console.log("handleUpdate-", e);
|
||||
//console.log("handleUpdate-", 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 "bknd/dist/styles.css";
|
||||
|
||||
export const prerender = false;
|
||||
const api = new Api({
|
||||
host: new URL(Astro.request.url).origin,
|
||||
headers: Astro.request.headers
|
||||
});
|
||||
import { getApi } from "bknd/adapter/astro";
|
||||
|
||||
const api = getApi(Astro, { mode: "dynamic" });
|
||||
const user = api.getUser();
|
||||
|
||||
export const prerender = false;
|
||||
---
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<Admin
|
||||
withProvider={{ user }}
|
||||
config={{ basepath: "/admin" }}
|
||||
config={{ basepath: "/admin", color_scheme: "dark" }}
|
||||
client:load
|
||||
/>
|
||||
</body>
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
---
|
||||
import { Api } from "bknd";
|
||||
const api = new Api({
|
||||
host: new URL(Astro.request.url).origin
|
||||
});
|
||||
import { getApi } from "bknd/adapter/astro";
|
||||
import Card from "../components/Card.astro";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
const api = getApi(Astro);
|
||||
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>
|
||||
<h2>Data</h2>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
|
||||
<a href="/admin">Admin</a> -
|
||||
<a href="/ssr">SSR (with auth)</a> -
|
||||
<a href="/">Home (static)</a>
|
||||
<style>
|
||||
.link-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
||||
gap: 2rem;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
---
|
||||
import { Api } from "bknd";
|
||||
const api = new Api({
|
||||
host: new URL(Astro.request.url).origin,
|
||||
headers: Astro.request.headers
|
||||
});
|
||||
import { getApi } from "bknd/adapter/astro";
|
||||
import Card from "../components/Card.astro";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
const api = getApi(Astro, { mode: "dynamic" });
|
||||
const { data } = await api.data.readMany("todos");
|
||||
const user = api.getUser();
|
||||
console.log("user", user);
|
||||
|
||||
export const prerender = false;
|
||||
---
|
||||
|
||||
<h1>SSR</h1>
|
||||
<h2>Data</h1>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
<Layout title="Welcome to Astro.">
|
||||
<p slot="context">Server Side Rendering</p>
|
||||
<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>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
|
||||
<a href="/admin">Admin</a> -
|
||||
<a href="/ssr">SSR (with auth)</a> -
|
||||
<a href="/">Home (static)</a>
|
||||
<style>
|
||||
.link-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
||||
gap: 2rem;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user