Initial commit
This commit is contained in:
commit
0397843a92
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/.direnv
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# Fresh build directory
|
||||||
|
_fresh/
|
||||||
|
# npm dependencies
|
||||||
|
node_modules/
|
49
.helix/languages.toml
Normal file
49
.helix/languages.toml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
[language-server.deno]
|
||||||
|
command = "deno"
|
||||||
|
args = ["lsp"]
|
||||||
|
config.hostInfo = "helix"
|
||||||
|
|
||||||
|
[[language]]
|
||||||
|
name = "javascript"
|
||||||
|
scope = "source.js"
|
||||||
|
injection-regex = "(js|javascript)"
|
||||||
|
language-id = "javascript"
|
||||||
|
file-types = ["js", "mjs", "cjs", "rules", "es6", "pac", "jakefile"]
|
||||||
|
shebangs = ["node"]
|
||||||
|
comment-token = "//"
|
||||||
|
language-servers = [ "deno" ]
|
||||||
|
indent = { tab-width = 2, unit = "\t" }
|
||||||
|
auto-format = true
|
||||||
|
|
||||||
|
[[language]]
|
||||||
|
name = "jsx"
|
||||||
|
scope = "source.jsx"
|
||||||
|
injection-regex = "jsx"
|
||||||
|
language-id = "javascriptreact"
|
||||||
|
file-types = ["jsx"]
|
||||||
|
comment-token = "//"
|
||||||
|
language-servers = [ "deno" ]
|
||||||
|
indent = { tab-width = 2, unit = "\t" }
|
||||||
|
grammar = "javascript"
|
||||||
|
auto-format = true
|
||||||
|
|
||||||
|
[[language]]
|
||||||
|
name = "typescript"
|
||||||
|
scope = "source.ts"
|
||||||
|
injection-regex = "(ts|typescript)"
|
||||||
|
file-types = ["ts", "mts", "cts"]
|
||||||
|
language-id = "typescript"
|
||||||
|
shebangs = ["deno", "ts-node"]
|
||||||
|
language-servers = [ "deno" ]
|
||||||
|
indent = { tab-width = 2, unit = "\t" }
|
||||||
|
auto-format = true
|
||||||
|
|
||||||
|
[[language]]
|
||||||
|
name = "tsx"
|
||||||
|
scope = "source.tsx"
|
||||||
|
injection-regex = "(tsx)"
|
||||||
|
language-id = "typescriptreact"
|
||||||
|
file-types = ["tsx"]
|
||||||
|
language-servers = [ "deno" ]
|
||||||
|
indent = { tab-width = 2, unit = "\t" }
|
||||||
|
auto-format = true
|
16
README.md
Normal file
16
README.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Fresh project
|
||||||
|
|
||||||
|
Your new Fresh project is ready to go. You can follow the Fresh "Getting
|
||||||
|
Started" guide here: https://fresh.deno.dev/docs/getting-started
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Make sure to install Deno: https://deno.land/manual/getting_started/installation
|
||||||
|
|
||||||
|
Then start the project:
|
||||||
|
|
||||||
|
```
|
||||||
|
deno task start
|
||||||
|
```
|
||||||
|
|
||||||
|
This will watch the project directory and restart as necessary.
|
12
components/Button.tsx
Normal file
12
components/Button.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { JSX } from 'preact'
|
||||||
|
import { IS_BROWSER } from '$fresh/runtime.ts'
|
||||||
|
|
||||||
|
export function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
{...props}
|
||||||
|
disabled={!IS_BROWSER || props.disabled}
|
||||||
|
class='px-2 py-1 border-gray-500 border-2 rounded bg-white hover:bg-gray-200 transition-colors'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
45
deno.json
Normal file
45
deno.json
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"lock": false,
|
||||||
|
"tasks": {
|
||||||
|
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
|
||||||
|
"cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -",
|
||||||
|
"manifest": "deno task cli manifest $(pwd)",
|
||||||
|
"start": "deno run -A --watch=static/,routes/ dev.ts",
|
||||||
|
"build": "deno run -A dev.ts build",
|
||||||
|
"preview": "deno run -A main.ts",
|
||||||
|
"update": "deno run -A -r https://fresh.deno.dev/update ."
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"rules": {
|
||||||
|
"tags": [
|
||||||
|
"fresh",
|
||||||
|
"recommended"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"**/_fresh/*"
|
||||||
|
],
|
||||||
|
"imports": {
|
||||||
|
"$fresh/": "https://deno.land/x/fresh@1.6.1/",
|
||||||
|
"preact": "https://esm.sh/preact@10.19.2",
|
||||||
|
"preact/": "https://esm.sh/preact@10.19.2/",
|
||||||
|
"@preact/signals": "https://esm.sh/*@preact/signals@1.2.1",
|
||||||
|
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.0",
|
||||||
|
"tailwindcss": "npm:tailwindcss@3.3.5",
|
||||||
|
"tailwindcss/": "npm:/tailwindcss@3.3.5/",
|
||||||
|
"tailwindcss/plugin": "npm:/tailwindcss@3.3.5/plugin.js",
|
||||||
|
"$models": "./models.ts",
|
||||||
|
"$std/": "https://deno.land/std@0.208.0/"
|
||||||
|
},
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "preact"
|
||||||
|
},
|
||||||
|
"fmt": {
|
||||||
|
"useTabs": true,
|
||||||
|
"semiColons": false,
|
||||||
|
"singleQuote": true
|
||||||
|
},
|
||||||
|
"nodeModulesDir": true
|
||||||
|
}
|
8
dev.ts
Executable file
8
dev.ts
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env -S deno run -A --watch=static/,routes/
|
||||||
|
|
||||||
|
import dev from '$fresh/dev.ts'
|
||||||
|
import config from './fresh.config.ts'
|
||||||
|
|
||||||
|
import '$std/dotenv/load.ts'
|
||||||
|
|
||||||
|
await dev(import.meta.url, './main.ts', config)
|
27
flake.lock
Normal file
27
flake.lock
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701718080,
|
||||||
|
"narHash": "sha256-6ovz0pG76dE0P170pmmZex1wWcQoeiomUZGggfH9XPs=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2c7f3c0fb7c08a0814627611d9d7d45ab6d75335",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2c7f3c0fb7c08a0814627611d9d7d45ab6d75335",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
23
flake.nix
Normal file
23
flake.nix
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs?rev=2c7f3c0fb7c08a0814627611d9d7d45ab6d75335";
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
}: let
|
||||||
|
inherit (self) outputs;
|
||||||
|
supportedSystems = ["x86_64-linux"];
|
||||||
|
forEachSupportedSystem = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
in {
|
||||||
|
devShells = forEachSupportedSystem (system: let
|
||||||
|
pkgs = import nixpkgs {inherit system;};
|
||||||
|
in {
|
||||||
|
deno-dev = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
deno
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
default = outputs.devShells.${system}.deno-dev;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
6
fresh.config.ts
Normal file
6
fresh.config.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { defineConfig } from '$fresh/server.ts'
|
||||||
|
import tailwind from '$fresh/plugins/tailwind.ts'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [tailwind()],
|
||||||
|
})
|
27
fresh.gen.ts
Normal file
27
fresh.gen.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// DO NOT EDIT. This file is generated by Fresh.
|
||||||
|
// This file SHOULD be checked into source version control.
|
||||||
|
// This file is automatically updated during development when running `dev.ts`.
|
||||||
|
|
||||||
|
import * as $_404 from './routes/_404.tsx'
|
||||||
|
import * as $_app from './routes/_app.tsx'
|
||||||
|
import * as $api_joke from './routes/api/joke.ts'
|
||||||
|
import * as $greet_name_ from './routes/greet/[name].tsx'
|
||||||
|
import * as $index from './routes/index.tsx'
|
||||||
|
import * as $Counter from './islands/Counter.tsx'
|
||||||
|
import { type Manifest } from '$fresh/server.ts'
|
||||||
|
|
||||||
|
const manifest = {
|
||||||
|
routes: {
|
||||||
|
'./routes/_404.tsx': $_404,
|
||||||
|
'./routes/_app.tsx': $_app,
|
||||||
|
'./routes/api/joke.ts': $api_joke,
|
||||||
|
'./routes/greet/[name].tsx': $greet_name_,
|
||||||
|
'./routes/index.tsx': $index,
|
||||||
|
},
|
||||||
|
islands: {
|
||||||
|
'./islands/Counter.tsx': $Counter,
|
||||||
|
},
|
||||||
|
baseUrl: import.meta.url,
|
||||||
|
} satisfies Manifest
|
||||||
|
|
||||||
|
export default manifest
|
16
islands/Counter.tsx
Normal file
16
islands/Counter.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import type { Signal } from '@preact/signals'
|
||||||
|
import { Button } from '../components/Button.tsx'
|
||||||
|
|
||||||
|
interface CounterProps {
|
||||||
|
count: Signal<number>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Counter(props: CounterProps) {
|
||||||
|
return (
|
||||||
|
<div class='flex gap-8 py-6'>
|
||||||
|
<Button onClick={() => props.count.value -= 1}>-1</Button>
|
||||||
|
<p class='text-3xl tabular-nums'>{props.count}</p>
|
||||||
|
<Button onClick={() => props.count.value += 1}>+1</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
13
main.ts
Normal file
13
main.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/// <reference no-default-lib="true" />
|
||||||
|
/// <reference lib="dom" />
|
||||||
|
/// <reference lib="dom.iterable" />
|
||||||
|
/// <reference lib="dom.asynciterable" />
|
||||||
|
/// <reference lib="deno.ns" />
|
||||||
|
|
||||||
|
import '$std/dotenv/load.ts'
|
||||||
|
|
||||||
|
import { start } from '$fresh/server.ts'
|
||||||
|
import manifest from './fresh.gen.ts'
|
||||||
|
import config from './fresh.config.ts'
|
||||||
|
|
||||||
|
await start(manifest, config)
|
13
models.ts
Normal file
13
models.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
type Name = string
|
||||||
|
|
||||||
|
export interface FamilyMember {
|
||||||
|
name: Name
|
||||||
|
avatarUrl?: URL
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ToDo {
|
||||||
|
emoji?: string
|
||||||
|
description: string
|
||||||
|
doneAt?: Date
|
||||||
|
assigneeName?: Name
|
||||||
|
}
|
27
routes/_404.tsx
Normal file
27
routes/_404.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Head } from '$fresh/runtime.ts'
|
||||||
|
|
||||||
|
export default function Error404() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>404 - Page not found</title>
|
||||||
|
</Head>
|
||||||
|
<div class='px-4 py-8 mx-auto bg-[#86efac]'>
|
||||||
|
<div class='max-w-screen-md mx-auto flex flex-col items-center justify-center'>
|
||||||
|
<img
|
||||||
|
class='my-6'
|
||||||
|
src='/logo.svg'
|
||||||
|
width='128'
|
||||||
|
height='128'
|
||||||
|
alt='the Fresh logo: a sliced lemon dripping with juice'
|
||||||
|
/>
|
||||||
|
<h1 class='text-4xl font-bold'>404 - Page not found</h1>
|
||||||
|
<p class='my-4'>
|
||||||
|
The page you were looking for doesn't exist.
|
||||||
|
</p>
|
||||||
|
<a href='/' class='underline'>Go back home</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
17
routes/_app.tsx
Normal file
17
routes/_app.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { type PageProps } from '$fresh/server.ts'
|
||||||
|
export default function App({ Component }: PageProps) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8' />
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
|
||||||
|
<title>homeman-deno</title>
|
||||||
|
<link rel='stylesheet' href='/styles.css' />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
meow
|
||||||
|
<Component />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
21
routes/api/joke.ts
Normal file
21
routes/api/joke.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { FreshContext } from '$fresh/server.ts'
|
||||||
|
|
||||||
|
// Jokes courtesy of https://punsandoneliners.com/randomness/programmer-jokes/
|
||||||
|
const JOKES = [
|
||||||
|
'Why do Java developers often wear glasses? They can\'t C#.',
|
||||||
|
'A SQL query walks into a bar, goes up to two tables and says “can I join you?”',
|
||||||
|
'Wasn\'t hard to crack Forrest Gump\'s password. 1forrest1.',
|
||||||
|
'I love pressing the F5 key. It\'s refreshing.',
|
||||||
|
'Called IT support and a chap from Australia came to fix my network connection. I asked “Do you come from a LAN down under?”',
|
||||||
|
'There are 10 types of people in the world. Those who understand binary and those who don\'t.',
|
||||||
|
'Why are assembly programmers often wet? They work below C level.',
|
||||||
|
'My favourite computer based band is the Black IPs.',
|
||||||
|
'What programme do you use to predict the music tastes of former US presidential candidates? An Al Gore Rhythm.',
|
||||||
|
'An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const handler = (_req: Request, _ctx: FreshContext): Response => {
|
||||||
|
const randomIndex = Math.floor(Math.random() * JOKES.length)
|
||||||
|
const body = JOKES[randomIndex]
|
||||||
|
return new Response(body)
|
||||||
|
}
|
5
routes/greet/[name].tsx
Normal file
5
routes/greet/[name].tsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { PageProps } from '$fresh/server.ts'
|
||||||
|
|
||||||
|
export default function Greet(props: PageProps) {
|
||||||
|
return <div>Hello {props.params.name}</div>
|
||||||
|
}
|
40
routes/index.tsx
Normal file
40
routes/index.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Handlers } from '$fresh/server.ts'
|
||||||
|
import { useSignal } from '@preact/signals'
|
||||||
|
import Counter from '../islands/Counter.tsx'
|
||||||
|
import { FamilyMember, ToDo } from '$models'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
familyMembers: FamilyMember[]
|
||||||
|
todos: ToDo[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handler: Handlers = {
|
||||||
|
async GET(_req, ctx) {
|
||||||
|
const resp = await ctx.render()
|
||||||
|
resp.headers.set('X-Custom-Header', 'Hello')
|
||||||
|
return resp
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const count = useSignal(3)
|
||||||
|
return (
|
||||||
|
<div class='px-4 py-8 mx-auto bg-[#86efac]'>
|
||||||
|
<div class='max-w-screen-md mx-auto flex flex-col items-center justify-center'>
|
||||||
|
<img
|
||||||
|
class='my-6'
|
||||||
|
src='/logo.svg'
|
||||||
|
width='128'
|
||||||
|
height='128'
|
||||||
|
alt='the Fresh logo: a sliced lemon dripping with juice'
|
||||||
|
/>
|
||||||
|
<h1 class='text-4xl font-bold'>Welcome to Fresh</h1>
|
||||||
|
<p class='my-4'>
|
||||||
|
Try updating this message in the
|
||||||
|
<code class='mx-2'>./routes/index.tsx</code> file, and refresh.
|
||||||
|
</p>
|
||||||
|
<Counter count={count} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
BIN
static/favicon.ico
Normal file
BIN
static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
6
static/logo.svg
Normal file
6
static/logo.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M34.092 8.845C38.929 20.652 34.092 27 30 30.5c1 3.5-2.986 4.222-4.5 2.5-4.457 1.537-13.512 1.487-20-5C2 24.5 4.73 16.714 14 11.5c8-4.5 16-7 20.092-2.655Z" fill="#FFDB1E"/>
|
||||||
|
<path d="M14 11.5c6.848-4.497 15.025-6.38 18.368-3.47C37.5 12.5 21.5 22.612 15.5 25c-6.5 2.587-3 8.5-6.5 8.5-3 0-2.5-4-5.183-7.75C2.232 23.535 6.16 16.648 14 11.5Z" fill="#fff" stroke="#FFDB1E"/>
|
||||||
|
<path d="M28.535 8.772c4.645 1.25-.365 5.695-4.303 8.536-3.732 2.692-6.606 4.21-7.923 4.83-.366.173-1.617-2.252-1.617-1 0 .417-.7 2.238-.934 2.326-1.365.512-4.223 1.29-5.835 1.29-3.491 0-1.923-4.754 3.014-9.122.892-.789 1.478-.645 2.283-.645-.537-.773-.534-.917.403-1.546C17.79 10.64 23 8.77 25.212 8.42c.366.014.82.35.82.629.41-.14 2.095-.388 2.503-.278Z" fill="#FFE600"/>
|
||||||
|
<path d="M14.297 16.49c.985-.747 1.644-1.01 2.099-2.526.566.121.841-.08 1.29-.701.324.466 1.657.608 2.453.701-.715.451-1.057.852-1.452 2.106-1.464-.611-3.167-.302-4.39.42Z" fill="#fff"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1 KiB |
3
static/styles.css
Normal file
3
static/styles.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
7
tailwind.config.ts
Normal file
7
tailwind.config.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { type Config } from 'tailwindcss'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
'{routes,islands,components}/**/*.{ts,tsx}',
|
||||||
|
],
|
||||||
|
} satisfies Config
|
Loading…
Reference in a new issue