Ethan Niser 2023-09-21 18:12:21 -05:00
parent f1c5467009
commit 22bff4dc17
7 changed files with 84 additions and 26 deletions

Binary file not shown.

@ -37,11 +37,12 @@
"@elysiajs/static": "^0.6.0",
"@elysiajs/swagger": "^0.6.2",
"@iconify-json/logos": "^1.1.37",
"@iconify-json/lucide": "^1.1.128",
"@libsql/client": "0.3.5-pre.9",
"@lucia-auth/adapter-sqlite": "^2.0.0",
"@t3-oss/env-core": "^0.6.1",
"@tlscipher/holt": "1.1.0",
"beth-stack": "0.0.24",
"beth-stack": "0.0.27",
"drizzle-orm": "^0.28.6",
"drizzle-typebox": "^0.1.1",
"elysia": "0.7.4",

@ -2,13 +2,8 @@ import { liveReloadScript } from "beth-stack/dev";
import { type PropsWithChildren } from "beth-stack/jsx";
import { config } from "../config";
const safeScript =
config.env.NODE_ENV === "development"
? liveReloadScript({
url: "https://upgraded-orbit-qw9457vrwv39669-3001.app.github.dev/ws",
})
: "";
config.env.NODE_ENV === "development" ? liveReloadScript() : "";
export const BaseHtml = ({ children }: PropsWithChildren) => (
<html>
@ -30,4 +25,4 @@ export const BaseHtml = ({ children }: PropsWithChildren) => (
{children}
</body>
</html>
);
);

@ -20,16 +20,14 @@ export function TweetCard({
<p class="text-gray-700" safe>
{content}
</p>
<span class="text-sm text-gray-500">
{createdAt.toLocaleString()}
</span>
<span class="text-sm text-gray-500">{createdAt.toLocaleString()}</span>
</div>
);
}
export async function TweetList() {
export async function InitialTweetList() {
const tweetData = await db.query.tweets.findMany({
limit: 10,
limit: 5,
orderBy: (tweets, { desc }) => [desc(tweets.createdAt)],
with: {
author: {
@ -40,12 +38,55 @@ export async function TweetList() {
},
});
const lastTweetTime = tweetData[tweetData.length - 1]?.createdAt;
return (
<>
<div class="space-y-4" id="tweetList">
{tweetData.map((tweet) => (
<TweetCard {...tweet} />
))}
<div
hx-get={`/api/tweets?after=${lastTweetTime?.toISOString()}`}
hx-swap="beforeend"
hx-target="#tweetList"
hx-trigger="revealed"
/>
</div>
</>
);
}
export async function AdditionalTweetList({ after }: { after: Date }) {
const tweetData = await db.query.tweets.findMany({
where: (tweets, { lt }) => lt(tweets.createdAt, after),
limit: 5,
orderBy: (tweets, { desc }) => [desc(tweets.createdAt)],
with: {
author: {
columns: {
handle: true,
},
},
},
});
const lastTweetTime = tweetData[tweetData.length - 1]?.createdAt;
return (
<div class="space-y-4" id="tweetList">
<>
{tweetData.map((tweet) => (
<TweetCard {...tweet} />
))}
</div>
{lastTweetTime && (
<div
hx-get={`/api/tweets?after=${lastTweetTime.toISOString()}`}
hx-swap="beforeend"
hx-target="#tweetList"
hx-trigger="revealed"
/>
)}
</>
);
}
@ -53,7 +94,12 @@ export function TweetCreationForm() {
return (
<div class="rounded-lg border p-4 shadow-md">
<h2 class="mb-4 text-xl font-bold">Create a new Tweet</h2>
<form hx-post="/api/tweets" hx-swap="afterbegin" hx-target="#tweetList" _="on submit target.reset()">
<form
hx-post="/api/tweets"
hx-swap="afterbegin"
hx-target="#tweetList"
_="on submit target.reset()"
>
<label class="mb-2 block text-sm font-bold" for="content">
Tweet:
</label>

@ -1,6 +1,6 @@
import { Elysia, t } from "elysia";
import { authed } from "../auth/middleware";
import { TweetCard } from "../components/tweets";
import { AdditionalTweetList, TweetCard } from "../components/tweets";
import { ctx } from "../context";
import { tweets } from "../db/schema/tweets";
@ -14,6 +14,21 @@ export const tweetsController = new Elysia({
return { session };
})
.get(
"/",
async ({ query: { after } }) => {
const date = new Date(after);
return <AdditionalTweetList after={date} />;
},
{
query: t.Object({
after: t.String({
format: "date-time",
}),
}),
},
)
.post(
"/",
async ({ session, db, body, set, log }) => {

@ -1,7 +1,8 @@
import { Suspense } from "beth-stack/jsx";
import { Elysia } from "elysia";
import { authed } from "../auth/middleware";
import { BaseHtml } from "../components/base";
import { TweetCreationForm, TweetList } from "../components/tweets";
import { InitialTweetList, TweetCreationForm } from "../components/tweets";
import { ctx } from "../context";
export const index = new Elysia()
@ -12,8 +13,8 @@ export const index = new Elysia()
return { session };
})
.get("/", async ({ html, session, db }) => {
return html(() => (
.get("/", async ({ htmlStream, session, db }) => {
return htmlStream(() => (
<BaseHtml>
<div class="flex flex-col items-center py-3">
{session ? (
@ -37,7 +38,7 @@ export const index = new Elysia()
Sign In
</a>
)}
<TweetList />
<InitialTweetList />
</div>
</BaseHtml>
));

@ -46,11 +46,11 @@ type PatchRoutes = RoutesByType<Schema, "patch">;
declare namespace JSX {
interface HtmlTag extends Htmx.Attributes {
["hx-get"]?: StartsWithApi<GetRoutes>;
["hx-post"]?: StartsWithApi<PostRoutes>;
["hx-put"]?: StartsWithApi<PutRoutes>;
["hx-delete"]?: StartsWithApi<DeleteRoutes>;
["hx-patch"]?: StartsWithApi<PatchRoutes>;
["hx-get"]?: StartsWithApi<GetRoutes> | (string & {});
["hx-post"]?: StartsWithApi<PostRoutes> | (string & {});
["hx-put"]?: StartsWithApi<PutRoutes> | (string & {});
["hx-delete"]?: StartsWithApi<DeleteRoutes> | (string & {});
["hx-patch"]?: StartsWithApi<PatchRoutes> | (string & {});
_?: string;
}
}