Skip to content

Commit

Permalink
Update colors, add hyperscript button, update README, update default …
Browse files Browse the repository at this point in the history
…port to 1234, add zod validation
  • Loading branch information
tireymorris committed Apr 30, 2024
1 parent 3845fdf commit 73dd0b4
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 59 deletions.
25 changes: 25 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 2021,
"sourceType": "module",
"babelOptions": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
},
"env": {
"browser": true,
"node": true
},
"plugins": [
"react"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"rules": {}
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,7 @@ Note: deploy `public/` with the executable, it contains the generated UnoCSS bui
- [Hono](https://hono.dev) is a robust web framework with great DX and performance
- [UnoCSS](https://unocss.dev/integrations/cli) is Tailwind-compatible and generates only the styles used in application code.
- [HTMX](https://htmx.org/reference/) gives 99% of the client-side interactivity most apps need.
- [hyperscript](http://hyperscript.org) is a scripting library for rapid application development.
- [zod](https://zod.dev/) is a powerful runtime validation library.

---
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"dependencies": {
"@unocss/preset-web-fonts": "^0.58.0",
"hono": "^3.6.3",
"unocss": "^0.58.0"
"unocss": "^0.58.0",
"zod": "^3.23.5"
},
"devDependencies": {
"@unocss/cli": "^0.56.5",
Expand Down
14 changes: 7 additions & 7 deletions public/styles/uno.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,23 @@
.gap-8{gap:2rem;}
.border{border-width:1px;}
.border-b-1{border-bottom-width:1px;}
.border-amber-300{--un-border-opacity:1;border-color:rgb(252 211 77 / var(--un-border-opacity));}
.border-gray-2{--un-border-opacity:1;border-color:rgb(229 231 235 / var(--un-border-opacity));}
.border-slate-200{--un-border-opacity:1;border-color:rgb(226 232 240 / var(--un-border-opacity));}
.focus\:border-blue-200:focus{--un-border-opacity:1;border-color:rgb(191 219 254 / var(--un-border-opacity));}
.rounded-md{border-radius:0.375rem;}
.border-none{border-style:none;}
.border-solid{border-style:solid;}
.border-b-solid{border-bottom-style:solid;}
.bg-amber-200{--un-bg-opacity:1;background-color:rgb(253 230 138 / var(--un-bg-opacity));}
.bg-amber-300{--un-bg-opacity:1;background-color:rgb(252 211 77 / var(--un-bg-opacity));}
.bg-amber-50{--un-bg-opacity:1;background-color:rgb(255 251 235 / var(--un-bg-opacity));}
.bg-amber-900{--un-bg-opacity:1;background-color:rgb(120 53 15 / var(--un-bg-opacity));}
.bg-blue-100{--un-bg-opacity:1;background-color:rgb(219 234 254 / var(--un-bg-opacity));}
.bg-gray-100{--un-bg-opacity:1;background-color:rgb(243 244 246 / var(--un-bg-opacity));}
.bg-red-400{--un-bg-opacity:1;background-color:rgb(248 113 113 / var(--un-bg-opacity));}
.bg-slate-200{--un-bg-opacity:1;background-color:rgb(226 232 240 / var(--un-bg-opacity));}
.bg-slate-700{--un-bg-opacity:1;background-color:rgb(51 65 85 / var(--un-bg-opacity));}
.bg-slate-800{--un-bg-opacity:1;background-color:rgb(30 41 59 / var(--un-bg-opacity));}
.bg-transparent{background-color:transparent;}
.bg-white{--un-bg-opacity:1;background-color:rgb(255 255 255 / var(--un-bg-opacity));}
.hover\:bg-red-400:hover{--un-bg-opacity:1;background-color:rgb(248 113 113 / var(--un-bg-opacity));}
.hover\:bg-amber-300:hover{--un-bg-opacity:1;background-color:rgb(252 211 77 / var(--un-bg-opacity));}
.hover\:bg-amber-400:hover{--un-bg-opacity:1;background-color:rgb(251 191 36 / var(--un-bg-opacity));}
.hover\:bg-slate-700:hover{--un-bg-opacity:1;background-color:rgb(51 65 85 / var(--un-bg-opacity));}
.fill-neutral-500{--un-fill-opacity:1;fill:rgb(115 115 115 / var(--un-fill-opacity));}
.fill-white{--un-fill-opacity:1;fill:rgb(255 255 255 / var(--un-fill-opacity));}
Expand All @@ -95,7 +96,6 @@
.text-base{font-size:1rem;line-height:1.5rem;}
.text-sm{font-size:0.875rem;line-height:1.25rem;}
.text-neutral-500{--un-text-opacity:1;color:rgb(115 115 115 / var(--un-text-opacity));}
.text-red-100{--un-text-opacity:1;color:rgb(254 226 226 / var(--un-text-opacity));}
.text-slate-400{--un-text-opacity:1;color:rgb(148 163 184 / var(--un-text-opacity));}
.text-white{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity));}
.hover\:text-white:hover{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity));}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function PinkButton({
}: Props) {
return (
<button
class={`flex cursor-pointer items-center justify-center gap-3 rounded-md border-none bg-red-400 px-4 py-2 text-base font-bold text-red-100 shadow-md hover:bg-red-400 hover:text-white ${className}`}
class={`flex cursor-pointer items-center justify-center gap-3 rounded-md border-none px-4 py-2 text-base font-bold shadow-md bg-amber-300 text-brown-800 hover:bg-amber-400 ${className}`}
{...rest}
>
{children}
Expand Down
17 changes: 8 additions & 9 deletions src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,18 @@ export default function Layout({ title, children, currentPath }: Props) {
<script src="https://unpkg.com/[email protected]" />
<link rel="stylesheet" href="/styles/uno.css" />
<script>htmx.config.globalViewTransitions = true</script>
<script src="https://unpkg.com/[email protected]"></script>
</head>

<style>{`* { box-sizing: border-box; margin: 0; outline: none; color: unset; }`}</style>

<body class="font-lato m-0 bg-gray-100 text-base">
<header class="border-b-solid border-b-1 fixed sticky flex w-full gap-4 border-slate-200 bg-slate-200 py-3 px-4 leading-5">
<a href="/" class="no-underline">
<h1>flapjack</h1>
<body class="font-lato m-0 bg-amber-50 text-base">
<header class="border-b-solid border-b-1 fixed sticky flex w-full gap-4 border-amber-300 bg-amber-200 py-3 px-4 leading-5">
<a href="/" class="no-underline text-brown-800">
<h1>🥞 flapjack</h1>
</a>
<div class="relative hidden md:block">
<Input
class="w-80 bg-white"
placeholder="Search clients, trips, groups, or invoices..."
/>
<Input class="w-80 bg-white" placeholder="Search ..." />
<span class="relative right-8 top-0.5 fill-neutral-500">
<Magnify />
</span>
Expand All @@ -45,10 +43,11 @@ export default function Layout({ title, children, currentPath }: Props) {

<Nav currentPath={currentPath} />

<main class="m-auto flex flex-col justify-center gap-8 py-4 pl-20 md:pl-60 md:pr-10">
<main class="m-auto flex flex-col justify-center gap-8 py-4 pl-20 md:pl-60 md:pr-10 bg-cream-200">
{children}
</main>
</body>
</html>
);
}
<script src="https://unpkg.com/[email protected]"></script>;
25 changes: 17 additions & 8 deletions src/components/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import NavItem from "./NavItem";
import PinkButton from "./PinkButton";
import Button from "./Button"; // Consider renaming if you change the color theme
import { routes } from "../routes";

export default function Nav({ currentPath }: { currentPath: string }) {
return (
<aside class="transition-width group fixed top-14 block h-full w-16 bg-slate-800 leading-5 duration-200 hover:w-56 md:w-56">
<aside class="transition-width group fixed top-14 block h-full w-16 bg-amber-900 leading-5 duration-200 hover:w-56 md:w-56 text-cream-100">
<nav>
<ul class="m-0 flex w-full flex-col items-center p-0">
<PinkButton class="items-start! justify-start! my-4 w-5/6 pl-5">
<span class="fixed pl-0.5">+</span>
<span class="relative left-10 m-0 p-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100 md:opacity-100">
CREATE
<Button class="items-start! justify-start! my-4 w-5/6 pl-5 ">
<span class="fixed pl-0.5 text-cream-200">+</span>
<span
_="on click call alert('flapjack!')"
class="relative left-10 m-0 p-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100 md:opacity-100"
>
CAKE
</span>
</PinkButton>
</Button>
{routes.map((route) => (
<NavItem currentPath={currentPath} route={route} />
<NavItem
currentPath={currentPath}
route={route}
style="bg-amber-200 hover:bg-amber-300 text-brown-900 hover:text-brown-700"
>
{route.label}
</NavItem>
))}
</ul>
</nav>
Expand Down
71 changes: 42 additions & 29 deletions src/routes/editUserInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Hono } from "hono";
import Input from "../components/Input.tsx";
import PinkButton from "../components/PinkButton.tsx";
import Button from "../components/Button.tsx";
import { addUser, createUsers, db } from "../db.ts";
import { z } from "zod";
import { HTTPException } from "hono/http-exception";

const app = new Hono();

Expand Down Expand Up @@ -37,7 +39,7 @@ app.get("/", async ({ html }) => {
<Input
class="bg-palette-highlight! sm:ml-4"
placeholder="Email"
type="text"
type="email"
name="email"
/>
</div>
Expand All @@ -59,9 +61,9 @@ app.get("/", async ({ html }) => {
name="lastName"
/>
</div>
<PinkButton class="btn btn-default" type="submit">
<Button class="btn btn-default" type="submit">
Submit
</PinkButton>
</Button>
</form>
</section>,
);
Expand All @@ -70,34 +72,45 @@ app.get("/", async ({ html }) => {
app.post("/:email", async (c) => {
const email = c.req.param("email");
const body = await c.req.parseBody();
const { email: newEmail, firstName, lastName } = body;

if (
typeof email !== "string" ||
typeof newEmail !== "string" ||
typeof firstName !== "string" ||
typeof lastName !== "string"
) {
throw new Error("Bad Request");
}

db.prepare(
"UPDATE USER SET email = $1, first_name = $2, last_name = $3 WHERE email = $4",
).run({
$1: newEmail,
$2: firstName,
$3: lastName,
$4: email,
const userSchema = z.object({
email: z.string().email(),
firstName: z.string(),
lastName: z.string(),
});

return c.html(
<div>
<p>Updated user info. </p>
<PinkButton class="w-40" hx-get="/editUser" hx-target="closest div">
Get User Info
</PinkButton>
</div>,
);
try {
const validatedBody = userSchema.parse(body);
const { email: newEmail, firstName, lastName } = validatedBody;

db.prepare(
"UPDATE USER SET email = $1, first_name = $2, last_name = $3 WHERE email = $4",
).run({
$1: newEmail,
$2: firstName,
$3: lastName,
$4: email,
});

return c.html(
<div>
<p>Updated user info. </p>
<Button class="w-40" hx-get="/editUser" hx-target="closest div">
Get User Info
</Button>
</div>,
);
} catch (error) {
console.error(error);
return c.html(
<div>
<p>Error: {error.errors[0]?.message ?? "Unknown error"}. </p>
<Button class="w-40" hx-get="/editUser" hx-target="closest div">
Get User Info
</Button>
</div>,
);
}
});

export default app;
11 changes: 7 additions & 4 deletions src/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Hono } from "hono";
import { serveStatic } from "hono/bun";
import { logger } from "hono/logger";
import Layout from "./components/Layout.tsx";
import PinkButton from "./components/PinkButton.tsx";
import Button from "./components/Button.tsx";

import editUserRoutes from "./routes/editUserInfo.tsx";

Expand All @@ -22,13 +22,16 @@ app.get("/settings", async ({ html }) =>
app.get("/dashboard", async ({ html }) =>
html(
<Layout title="flapjack | dashboard" currentPath="/dashboard">
<PinkButton class="w-40" hx-get="/editUser">
<Button class="w-40" hx-get="/editUser">
Get User Info
</PinkButton>
</Button>
</Layout>,
),
);

app.route("/editUser", editUserRoutes);

export default app;
export default {
port: process.env.PORT || 1234,
fetch: app.fetch,
};

0 comments on commit 73dd0b4

Please sign in to comment.