Skip to content

Commit 47d9f6b

Browse files
authored
feat(templates): add elysia template (#16)
* feat(templates): add elysia template * fix(templates): pr fixes
1 parent 565ffa7 commit 47d9f6b

24 files changed

Lines changed: 596 additions & 32 deletions

templates/elysia/.gitignore

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env.local
29+
.env.development.local
30+
.env.test.local
31+
.env.production.local
32+
33+
# vercel
34+
.vercel
35+
36+
**/*.trace
37+
**/*.zip
38+
**/*.tar.gz
39+
**/*.tgz
40+
**/*.log
41+
package-lock.json
42+
**/*.bun

templates/elysia/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Elysia with Bun runtime
2+
3+
## Getting Started
4+
5+
To get started with this template, simply paste this command into your terminal:
6+
7+
```bash
8+
bun create elysia ./elysia-example
9+
```
10+
11+
## Development
12+
13+
To start the development server run:
14+
15+
```bash
16+
bun run dev
17+
```
18+
19+
Open http://localhost:3000/ with your browser to see the result.

templates/elysia/bun.lock

Lines changed: 235 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

templates/elysia/index.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Ilha</title>
6+
<link rel="icon" href="/static/favicon.svg" />
7+
<meta content="width=device-width, initial-scale=1" name="viewport" />
8+
<link rel="stylesheet" href="/app.css" />
9+
<link
10+
href="https://cdn.jsdelivr.net/npm/@faith-tools/sensible-ui@1.0.5/dist/sensible-ui.min.css"
11+
type="text/css"
12+
rel="stylesheet"
13+
/>
14+
</head>
15+
<body>
16+
<div id="app"></div>
17+
<script type="module" src="/client.js"></script>
18+
</body>
19+
</html>

templates/elysia/package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "elysia",
3+
"version": "1.0.50",
4+
"type": "module",
5+
"module": "src/server.js",
6+
"scripts": {
7+
"dev": "tsdown --watch --on-success \"bun dist/server.mjs\"",
8+
"build": "tsdown",
9+
"start": "bun dist/server.mjs"
10+
},
11+
"dependencies": {
12+
"@elysiajs/html": "^1.4.0",
13+
"@elysiajs/static": "^1.4.9",
14+
"@ilha/router": "https://pkg.pr.new/@ilha/router@565ffa7",
15+
"elysia": "^1.4.28",
16+
"ilha": "https://pkg.pr.new/ilha@565ffa7"
17+
},
18+
"devDependencies": {
19+
"bun-types": "latest",
20+
"tsdown": "^0.21.9"
21+
}
22+
}

templates/elysia/src/app.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.container {
2+
max-width: 64rem;
3+
margin: 0 auto;
4+
padding: 0 1rem;
5+
}
6+
7+
.navbar {
8+
padding: 0.5rem 1rem;
9+
}

templates/elysia/src/client.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { router } from "@ilha/router";
2+
3+
import Layout from "./pages/+layout.js";
4+
import HomePage from "./pages/index.js";
5+
import LearnPage from "./pages/learn.js";
6+
import notFoundPage from "./pages/not-found.js";
7+
8+
router()
9+
.route("/", Layout(HomePage))
10+
.route("/learn", Layout(LearnPage))
11+
.route("/**", Layout(notFoundPage))
12+
.mount("#app");
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { isActive } from "@ilha/router";
2+
import type { LayoutHandler } from "@ilha/router/vite";
3+
import ilha, { html } from "ilha";
4+
5+
export default ((children) =>
6+
ilha.slot("children", children).render(
7+
({ slots }) => html`
8+
<nav class="container navbar x-stack">
9+
<a href="/" class="button" data-variant="${isActive("/") ? "secondary" : "ghost"}">Home</a>
10+
<a href="/learn" class="button" data-variant="${isActive("/learn") ? "secondary" : "ghost"}">Learn</a>
11+
</nav>
12+
<main class="container">
13+
${slots.children()}
14+
</main>
15+
`,
16+
)) satisfies LayoutHandler;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import ilha, { html, raw } from "ilha";
2+
3+
const DEFAULT_TODOS = [
4+
{ text: "Start Ilha Dev Server", completed: true },
5+
{ text: "Develop my Ilha app", completed: false },
6+
{ text: "Deploy my Ilha app", completed: false },
7+
];
8+
9+
type Todo = { text: string; completed: boolean };
10+
11+
const addTodo = (todos: Todo[], text: string): Todo[] => [...todos, { text, completed: false }];
12+
13+
const toggleTodo = (todos: Todo[], index: number): Todo[] =>
14+
todos.map((todo, i) => (i === index ? { ...todo, completed: !todo.completed } : todo));
15+
16+
const deleteTodo = (todos: Todo[], index: number): Todo[] => todos.filter((_, i) => i !== index);
17+
18+
const getIndex = (target: Element) => Number.parseInt(target.getAttribute("data-index")!);
19+
20+
const todoItem = (todo: Todo, index: number) => html`
21+
<div class="item x-stack">
22+
<input id="todo-${index}" type="checkbox" data-index="${index}" ${todo.completed ? "checked" : ""} data-todo-checkbox />
23+
<label for="todo-${index}" style="${todo.completed ? "flex:1;text-decoration:line-through" : "flex:1;"}">${todo.text}</label>
24+
<button data-action="delete" data-index="${index}" type="button" data-variant="secondary">Delete</button>
25+
</div>
26+
`;
27+
28+
export default ilha
29+
.state("todos", DEFAULT_TODOS)
30+
.state("serverResult", "")
31+
.on("[data-todo-checkbox]@change", ({ state, target }) => {
32+
state.todos(toggleTodo(state.todos(), getIndex(target)));
33+
})
34+
.on("[data-todo-form]@submit", ({ event, target, state }) => {
35+
event.preventDefault();
36+
const form = target as HTMLFormElement;
37+
const text = new FormData(form).get("todo")!.toString().trim();
38+
if (!text) return;
39+
state.todos(addTodo(state.todos(), text));
40+
form.reset();
41+
})
42+
.on("[data-action=delete]@click", ({ state, target }) => {
43+
state.todos(deleteTodo(state.todos(), getIndex(target)));
44+
})
45+
.on("[data-action=fetch_component]@click", async ({ state }) => {
46+
const req = await fetch("/server-island");
47+
const html = await req.text();
48+
state.serverResult(html);
49+
})
50+
.render(
51+
({ state }) =>
52+
html`
53+
<div class="y-stack">
54+
<div class="card">
55+
<header>
56+
<h2>To Do</h2>
57+
</header>
58+
<section class="y-stack">
59+
<form data-todo-form>
60+
<div class="x-stack">
61+
<input
62+
name="todo"
63+
type="text"
64+
placeholder="Add a new todo"
65+
style="flex-shrink: 1;"
66+
/>
67+
<button type="submit">Add</button>
68+
</div>
69+
</form>
70+
<div class="y-stack">${state.todos().map(todoItem)}</div>
71+
</section>
72+
</div>
73+
<div class="x-stack">
74+
<button data-action="fetch_component" data-variant="secondary">Fetch Server Side Component</button>
75+
${raw(state.serverResult())}
76+
</div>
77+
</div>
78+
`,
79+
);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import ilha from "ilha";
2+
import { html } from "ilha";
3+
4+
const LEARN_ITEMS = [
5+
{
6+
title: "Documentation",
7+
description: "Learn how to use Ilha.",
8+
href: "https://ilha.build/docs",
9+
icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWJvb2staWNvbiBsdWNpZGUtYm9vayI+PHBhdGggZD0iTTQgMTkuNXYtMTVBMi41IDIuNSAwIDAgMSA2LjUgMkgxOWExIDEgMCAwIDEgMSAxdjE4YTEgMSAwIDAgMS0xIDFINi41YTEgMSAwIDAgMSAwLTVIMjAiLz48L3N2Zz4=",
10+
},
11+
{
12+
title: "Discord",
13+
description: "Join our Discord server.",
14+
href: "https://discord.gg/WnVTMCTz74",
15+
icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWxpbmstaWNvbiBsdWNpZGUtbGluayI+PHBhdGggZD0iTTEwIDEzYTUgNSAwIDAgMCA3LjU0LjU0bDMtM2E1IDUgMCAwIDAtNy4wNy03LjA3bC0xLjcyIDEuNzEiLz48cGF0aCBkPSJNMTQgMTFhNSA1IDAgMCAwLTcuNTQtLjU0bC0zIDNhNSA1IDAgMCAwIDcuMDcgNy4wN2wxLjcxLTEuNzEiLz48L3N2Zz4=",
16+
},
17+
{
18+
title: "x.com",
19+
description: "Follow us on X.",
20+
href: "https://x.com/ilha_js",
21+
icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWxpbmstaWNvbiBsdWNpZGUtbGluayI+PHBhdGggZD0iTTEwIDEzYTUgNSAwIDAgMCA3LjU0LjU0bDMtM2E1IDUgMCAwIDAtNy4wNy03LjA3bC0xLjcyIDEuNzEiLz48cGF0aCBkPSJNMTQgMTFhNSA1IDAgMCAwLTcuNTQtLjU0bC0zIDNhNSA1IDAgMCAwIDcuMDcgNy4wN2wxLjcxLTEuNzEiLz48L3N2Zz4=",
22+
},
23+
];
24+
25+
const learnItem = (item: (typeof LEARN_ITEMS)[0]) =>
26+
html`
27+
<a href="${item.href}" class="item" target="_blank" rel="noopener noreferrer">
28+
<section>
29+
<h3>${item.title}</h3>
30+
<p>${item.description}</p>
31+
</section>
32+
<img
33+
src="${item.icon}"
34+
alt="${item.title}"
35+
class="icon"
36+
/>
37+
</a>
38+
`;
39+
40+
export default ilha.render(
41+
() =>
42+
html`
43+
<h2>Learn Ilha</h2>
44+
<div class="y-stack">
45+
${LEARN_ITEMS.map(learnItem)}
46+
</div>
47+
`,
48+
);

0 commit comments

Comments
 (0)