Skip to content

Commit

Permalink
Initial commit of Beacon Plotter
Browse files Browse the repository at this point in the history
  • Loading branch information
dalegaard committed Nov 16, 2023
0 parents commit 4fc03ee
Show file tree
Hide file tree
Showing 23 changed files with 1,073 additions and 0 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Deploy content to Pages

on:
push:
branches: ["master"]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: true

jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install bun
uses: oven-sh/setup-bun@v1
- name: Build all tools
run: ./build.sh
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: "dist/"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
24 changes: 24 additions & 0 deletions beacon_plotter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
28 changes: 28 additions & 0 deletions beacon_plotter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Usage

```bash
$ npm install # or pnpm install or yarn install
```

### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)

## Available Scripts

In the project directory, you can run:

### `npm run dev`

Runs the app in the development mode.<br>
Open [http://localhost:5173](http://localhost:5173) to view it in the browser.

### `npm run build`

Builds the app for production to the `dist` folder.<br>
It correctly bundles Solid in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.<br>
Your app is ready to be deployed!

## Deployment

Learn more about deploying your application with the [documentations](https://vitejs.dev/guide/static-deploy.html)
Binary file added beacon_plotter/bun.lockb
Binary file not shown.
12 changes: 12 additions & 0 deletions beacon_plotter/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Beacon Plotter</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
33 changes: 33 additions & 0 deletions beacon_plotter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "beacon_plotter",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {},
"devDependencies": {
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@solid-primitives/resize-observer": "^2.0.22",
"@types/d3-axis": "^3.0.6",
"@types/d3-scale": "^4.0.8",
"@types/d3-selection": "^3.0.10",
"@types/luxon": "^3.3.4",
"autoprefixer": "^10.4.16",
"d3-axis": "^3.0.0",
"d3-selection": "^3.0.0",
"eventemitter3": "^5.0.1",
"luxon": "^3.4.4",
"postcss": "^8.4.31",
"solid-fa": "^0.2.0",
"solid-js": "^1.7.8",
"tailwindcss": "^3.3.5",
"timechart": "beta",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-plugin-solid": "^2.7.0"
}
}
6 changes: 6 additions & 0 deletions beacon_plotter/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
1 change: 1 addition & 0 deletions beacon_plotter/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions beacon_plotter/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
243 changes: 243 additions & 0 deletions beacon_plotter/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import {
Accessor,
Show,
createEffect,
createSignal,
onCleanup,
For,
ValidComponent,
createMemo,
Switch,
Match,
} from "solid-js";
import { createStore } from "solid-js/store";
import { Fa } from "solid-fa";
import { faGear } from "@fortawesome/free-solid-svg-icons";
import "./App.css";
import { Dynamic } from "solid-js/web";
import { BeaconStreamDumper, Sample } from "./stream_dumper";
import { SampleChart } from "./sample_chart";

const precision_rounder = (d: number) => {
return (v: number) => {
return v.toFixed(d);
};
};
const rp1 = precision_rounder(1);
const rp2 = precision_rounder(2);
const rp3 = precision_rounder(3);
const rp4 = precision_rounder(4);

interface DataFieldProps {
last_sample: Accessor<Sample>;
}

const DataFields: [string, ValidComponent][] = [
["Dist", (props: DataFieldProps) => <>{rp4(props.last_sample().dist)}</>],
["Freq", (props: DataFieldProps) => <>{rp3(props.last_sample().dist)}</>],
[
"Pos",
(props: DataFieldProps) => (
<Show
when={props.last_sample().pos}
fallback={<span class="text-yellow-800">-</span>}
>
{props.last_sample().pos!.map(rp2).join(",") || "-"}
</Show>
),
],
["Temp", (props: DataFieldProps) => <>{rp1(props.last_sample().temp)}</>],
["Time", (props: DataFieldProps) => <>{rp3(props.last_sample().time)}</>],
[
"Vel",
(props: DataFieldProps) => {
const vel = createMemo(() => {
const vel = props.last_sample()?.vel;
return vel ? rp2(vel) : undefined;
});
return (
<Show
when={vel() != undefined}
fallback={<span class="text-yellow-800">-</span>}
>
{vel()!}
</Show>
);
},
],
];

function App() {
const [last_sample, set_last_sample] = createSignal<Sample>();

const saved_settings = localStorage.getItem("settings");
let init_settings = {
domain: "",
port: 80,
secure: false,
};
if (saved_settings) {
init_settings = { ...init_settings, ...JSON.parse(saved_settings) };
}
const [settings, set_settings] = createStore(init_settings);

createEffect(() => {
localStorage.setItem("settings", JSON.stringify(settings));
});

const source_url = createMemo(() => {
if (!settings.domain || !settings.port) return undefined;
return `ws${settings.secure ? "s" : ""}://${settings.domain}:${
settings.port
}/klippysocket`;
});

const [raw_source, set_raw_source] = createSignal<BeaconStreamDumper>();
const connect = () => {
const url = source_url();
if (url) {
set_raw_source(new BeaconStreamDumper(url));
}
};

const source = createMemo(() => {
const src = raw_source();
if (!src || !src.state.receiving) return undefined;
return src;
});

createEffect(() => {
const sd = source();
if (!sd) return;
const cb = (samples: Sample[]) => {
if (samples.length) {
set_last_sample(samples[samples.length - 1]);
}
};
sd.addListener("samples", cb);
onCleanup(() => sd.removeListener("samples", cb));
});

const [highlighted_point, set_highlighted_point] = createSignal<
Sample | undefined
>();

return (
<Switch>
<Match when={!source()}>
<div class="absolute inset-0 flex flex-col justify-center bg-slate-950 text-black">
<div class="mx-auto container max-w-screen-sm bg-gray-300 rounded-lg p-4">
<Show
when={!raw_source()?.state.connected}
fallback={
<h1 class="text-lg font-bold">Awaiting initial data</h1>
}
>
<h1 class="text-xl font-bold mb-3">Connection details</h1>
<div class="mb-3">
<label
class="block mb-2 text-sm font-medium text-gray-900"
for="ip"
>
Moonraker IP address or domain
</label>
<input
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
type="ip"
id="ip"
value={settings.domain}
onInput={(e) => set_settings("domain", e.currentTarget.value)}
/>
</div>
<div class="mb-3">
<label
class="block mb-2 text-sm font-medium text-gray-900"
for="ip"
>
Moonraker port
</label>
<input
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
type="ip"
id="ip"
value={settings.port}
onInput={[set_settings, "port"]}
/>
</div>
<div class="flex flex-row items-center gap-3">
<button
type="button"
classList={{
"text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center w-max":
true,
"bg-gray-700": !source_url(),
}}
onClick={connect}
disabled={raw_source()?.state.connecting || !source_url()}
>
<Show when={raw_source()?.state.connecting}>
<Fa
icon={faGear}
spin={true}
classList={{ "inline-block": true, "mr-2": true }}
/>
</Show>
Connect
</button>
<Show when={raw_source()?.state.last_error}>
{(error) => (
<div class="text-red-600 font-bold">
Connection error: {error()}
</div>
)}
</Show>
</div>
</Show>
</div>
</div>
</Match>
<Match when={source()}>
{(source) => (
<div class="absolute inset-0 flex flex-col bg-slate-950 text-yellow-300">
<SampleChart
class="grow"
set_highlighted_point={set_highlighted_point}
source={source}
/>
<Show when={highlighted_point() || last_sample()}>
{(last_sample) => (
<div>
<div
class="text-xs font-extrabold bg-slate-950 w-max mx-2"
style={{ "margin-bottom": "-8px" }}
>
<Show when={highlighted_point()} fallback={"Last sample"}>
Sample under cursor
</Show>
</div>
<div class="grid grid-cols-6 px-2 pt-3 border-t border-slate-600">
<For each={DataFields}>
{([title, formatter]) => (
<div class="flex-col odd:bg-slate-900 px-2">
<div class="font-extrabold text-sm">{title}</div>
<div>
<Dynamic
component={formatter}
last_sample={last_sample}
/>
</div>
</div>
)}
</For>
</div>
</div>
)}
</Show>
</div>
)}
</Match>
</Switch>
);
}

export default App;
Loading

0 comments on commit 4fc03ee

Please sign in to comment.