on master help sign in
init commit
commit5651ef8b4b8c1d6e55408788d3367a4a8e8dcd56 authorHunter Miller <hunter@hmiller.dev> dateMon 27 Jun 2022, 18:21 (4 years ago) parent80f91a0
24 files changed+345
README.md+45 desk/desk.bill+1 desk/desk.docket-0+9 desk/sys.kelvin+1 ui/.gitignore+8 ui/index.html+17 ui/package.json+29 ui/postcss.config.js+6 ui/src/app.tsx+44 ui/src/assets/android-chrome-512x512.png ui/src/assets/apple-touch-icon.png ui/src/assets/favicon.ico ui/src/assets/favicon.svg+12 ui/src/assets/manifest.json+14 ui/src/assets/safari-pinned-tab.svg+54 ui/src/components/AppTile.tsx+29 ui/src/env.d.ts+7 ui/src/index.css+3 ui/src/main.tsx+11 ui/src/vite-env.d.ts+1 ui/src/window.ts+8 ui/tailwind.config.js+13 ui/tsconfig.json+19 ui/vite.config.ts+14
README.mdnew file+45
@@ -0,0 +1,45 @@
1+# seek
2+
3+## Desk
4+
5+The desk currently has the minimum amount of files necessary to distribute an application and should be distributable immediately. Any further Hoon development should happen here.
6+
7+TODO: Add further documentation on beginning Hoon development
8+
9+## UI
10+
11+seek is built primarily using [React], [Typescript], and [Tailwind CSS]. [Vite] ensures that all code and assets are loaded appropriately, bundles the application for distribution and provides a functional dev environment.
12+
13+### Getting Started
14+
15+To get started using seek first you need to run `npm install` inside the `ui` directory.
16+
17+To develop you'll need a running ship to point to. To do so you first need to add a `.env.local` file to the `ui` directory. This file will not be committed. Adding `VITE_SHIP_URL={URL}` where **{URL}** is the URL of the ship you would like to point to, will allow you to run `npm run dev`. This will proxy all requests to the ship except for those powering the interface, allowing you to see live data.
18+
19+Regardless of what you run to develop, Vite will hot-reload code changes as you work so you don't have to constantly refresh.
20+
21+### Deploying
22+
23+To deploy, run `npm run build` in the `ui` directory which will bundle all the code and assets into the `dist/` folder. This can then be made into a glob by doing the following:
24+
25+1. Create or launch an urbit using the -F flag
26+2. On that urbit, if you don't already have a desk to run from, run `|merge %work our %base` to create a new desk and mount it with `|mount %work`.
27+3. Now the `%work` desk is accessible through the host OS's filesystem as a directory of that urbit's pier ie `~/zod/work`.
28+4. From the `ui` directory you can run `rsync -avL --delete dist/ ~/zod/work/seek` where `~/zod` is your fake urbit's pier.
29+5. Once completed you can then run `|commit %work` on your urbit and you should see your files logged back out from the dojo.
30+6. Now run `=dir /=garden` to switch to the garden desk directory
31+7. You can now run `-make-glob %work /seek` which will take the folder where you just added files and create a glob which can be thought of as a sort of bundle. It will be output to `~/zod/.urb/put`.
32+8. If you navigate to `~/zod/.urb/put` you should see a file that looks like this `glob-0v5.fdf99.nph65.qecq3.ncpjn.q13mb.glob`. The characters between `glob-` and `.glob` are a hash of the glob's contents.
33+9. Now that we have the glob it can be uploaded to any publicly available HTTP endpoint that can serve files. This allows the glob to distributed over HTTP.
34+10. Once you've uploaded the glob, you should then update the corresponding entry in the docket file at `desk/desk.docket-0`. Both the full URL and the hash should be updated to match the glob we just created, on the line that looks like this:
35+
36+```hoon
37+ glob-http+['https://bootstrap.urbit.org/glob-0v5.fdf99.nph65.qecq3.ncpjn.q13mb.glob' 0v5.fdf99.nph65.qecq3.ncpjn.q13mb]
38+```
39+
40+11. This can now be safely committed and deployed.
41+
42+[react]: https://reactjs.org/
43+[typescript]: https://www.typescriptlang.org/
44+[tailwind css]: https://tailwindcss.com/
45+[vite]: https://vitejs.dev/
desk/desk.billnew file+1
@@ -0,0 +1 @@
1+~
desk/desk.docket-0new file+9
@@ -0,0 +1,9 @@
1+:~ title+'seek'
2+ info+'An Urbit app that does great things'
3+ color+0x2e.4347
4+ glob-http+['https://bootstrap.urbit.org/glob-0v5.hurm4.ejod5.ngg9h.iub9i.n1j7o.glob' 0v5.hurm4.ejod5.ngg9h.iub9i.n1j7o]
5+ base+'seek'
6+ version+[0 0 1]
7+ website+'https://github.com'
8+ license+'MIT'
9+==
desk/sys.kelvinnew file+1
@@ -0,0 +1 @@
1+[%zuse 420]
ui/.gitignorenew file+8
@@ -0,0 +1,8 @@
1+node_modules
2+.DS_Store
3+dist
4+dist-ssr
5+*.local
6+stats.html
7+.eslintcache
8+.vercel
ui/index.htmlnew file+17
@@ -0,0 +1,17 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>seek</title>
7+ <meta name="theme-color" content="#ffffff" />
8+ <link rel="icon" href="/src/assets/favicon.svg" sizes="any" type="image/svg+xml" />
9+ <link rel="mask-icon" href="/src/assets/safari-pinned-tab.svg" color="#000000" />
10+ <link rel="apple-touch-icon" sizes="180x180" href="/src/assets/apple-touch-icon.png" />
11+ <link rel="manifest" href="/src/assets/manifest.json" />
12+ </head>
13+ <body class="font-sans text-gray-900 bg-white antialiased">
14+ <div id="app"></div>
15+ <script type="module" src="/src/main.tsx"></script>
16+ </body>
17+</html>
ui/package.jsonnew file+29
@@ -0,0 +1,29 @@
1+{
2+ "name": "seek",
3+ "version": "0.0.0",
4+ "private": true,
5+ "scripts": {
6+ "dev": "vite",
7+ "build": "tsc && vite build",
8+ "serve": "vite preview",
9+ "test": "tsc --noEmit",
10+ "tsc": "tsc --noEmit"
11+ },
12+ "dependencies": {
13+ "@urbit/api": "^2.0.0",
14+ "@urbit/http-api": "^2.0.0",
15+ "react": "^17.0.2",
16+ "react-dom": "^17.0.2"
17+ },
18+ "devDependencies": {
19+ "@types/react": "^17.0.0",
20+ "@types/react-dom": "^17.0.0",
21+ "@urbit/vite-plugin-urbit": "^0.8.0",
22+ "@vitejs/plugin-react-refresh": "^1.3.1",
23+ "autoprefixer": "^10.3.7",
24+ "postcss": "^8.3.9",
25+ "tailwindcss": "^2.2.16",
26+ "typescript": "^4.3.2",
27+ "vite": "^2.6.7"
28+ }
29+}
ui/postcss.config.jsnew file+6
@@ -0,0 +1,6 @@
1+module.exports = {
2+ plugins: [
3+ require('tailwindcss'),
4+ require('autoprefixer'),
5+ ]
6+}
ui/src/app.tsxnew file+44
@@ -0,0 +1,44 @@
1+import React, { useEffect, useState } from 'react';
2+import Urbit from '@urbit/http-api';
3+import { Charges, ChargeUpdateInitial, scryCharges } from '@urbit/api';
4+import { AppTile } from './components/AppTile';
5+
6+const api = new Urbit('', '', window.desk);
7+api.ship = window.ship;
8+
9+export function App() {
10+ const [apps, setApps] = useState<Charges>();
11+
12+ useEffect(() => {
13+ async function init() {
14+ const charges = (await api.scry<ChargeUpdateInitial>(scryCharges)).initial;
15+ setApps(charges);
16+ }
17+
18+ init();
19+ }, []);
20+
21+ return (
22+ <main className="flex items-center justify-center min-h-screen">
23+ <div className="max-w-md space-y-6 py-20">
24+ <h1 className="text-3xl font-bold">Welcome to seek</h1>
25+ <p>Here&apos;s your urbit&apos;s installed apps:</p>
26+ {apps && (
27+ <ul className="space-y-4">
28+ {Object.entries(apps).map(([desk, app]) => (
29+ <li key={desk} className="flex items-center space-x-3 text-sm leading-tight">
30+ <AppTile {...app} />
31+ <div className="flex-1 text-black">
32+ <p>
33+ <strong>{app.title || desk}</strong>
34+ </p>
35+ {app.info && <p>{app.info}</p>}
36+ </div>
37+ </li>
38+ ))}
39+ </ul>
40+ )}
41+ </div>
42+ </main>
43+ );
44+}
ui/src/assets/android-chrome-512x512.pngnew file

Binary file not shown.

ui/src/assets/apple-touch-icon.pngnew file

Binary file not shown.

ui/src/assets/favicon.iconew file

Binary file not shown.

ui/src/assets/favicon.svgnew file+12
@@ -0,0 +1,12 @@
1+<svg width="513" height="513" viewBox="0 0 513 513" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<style>
3+.icon-color { fill: #000000; }
4+@media (prefers-color-scheme: dark) {
5+ .icon-color { fill: #ffffff; }
6+}
7+</style>
8+<path d="M247.634 122.758C247.634 147.519 238.15 162.538 219.182 171.468C198.239 181.21 184.804 197.853 178.876 220.584C172.159 245.751 153.981 260.364 129.481 259.552C109.723 259.146 94.7075 249.404 86.014 231.138C79.2963 216.931 70.6028 204.753 56.7723 197.041C50.4497 193.388 43.732 190.952 36.6192 188.923C16.4661 183.24 1.84525 166.597 0.264615 145.896C-1.71118 121.135 7.37747 103.274 27.5305 93.1266C49.6594 82.5728 63.49 65.1184 69.4173 41.1695C75.3447 16.8145 95.8929 2.60752 122.369 4.6371C137.385 5.85484 148.844 13.5672 157.538 25.7447C163.465 34.2689 168.602 43.199 174.529 51.3173C181.642 61.4652 191.126 67.9598 202.586 72.019C208.118 74.0486 214.045 76.0781 219.182 78.9195C238.15 88.6615 247.634 104.492 247.634 122.758Z" class="icon-color" />
9+<path d="M512.01 355.757C511.615 372.806 503.712 387.824 486.325 396.349C463.406 407.714 449.18 425.981 442.067 450.335C435.745 471.037 419.543 484.026 398.6 485.65C377.657 487.274 359.084 476.72 350.391 457.236C340.512 434.505 323.915 420.704 300.601 414.209C258.714 403.249 254.762 350.48 279.262 328.561C283.609 324.908 288.351 321.254 293.488 318.819C314.036 308.671 327.076 292.029 333.399 270.109C338.931 250.219 350.786 236.824 370.939 232.765C393.858 228.3 415.197 235.2 426.261 259.555C436.535 282.287 453.132 295.682 476.446 302.582C500.551 309.889 512.01 326.937 512.01 355.757Z" class="icon-color" />
10+<path d="M463.786 51.3199C462.6 58.2204 461.415 65.121 459.439 71.6156C453.117 93.1291 454.697 113.425 466.157 132.909C476.431 150.363 476.036 168.629 465.762 185.678C455.883 202.32 440.472 210.033 421.899 210.033C417.157 210.033 412.415 208.815 408.069 207.191C384.359 199.073 361.44 200.697 339.706 214.498C310.069 233.17 271.739 206.379 268.973 178.371C268.182 169.441 268.182 160.511 271.344 152.393C280.037 130.067 276.481 109.366 266.997 89.07C262.65 80.1398 259.094 70.8038 259.094 60.6559C259.489 27.3709 290.311 3.42188 321.529 11.9461C331.408 14.7875 341.287 18.4407 351.956 18.4407C364.206 18.4407 374.875 14.3816 385.94 9.10469C393.052 5.45146 400.956 2.20414 408.859 0.580478C434.544 -3.88459 461.02 18.0348 462.996 44.8252C462.996 47.2607 463.391 49.2903 463.391 51.7258C463.391 51.3199 463.786 51.3199 463.786 51.3199Z" class="icon-color" />
11+<path d="M235.757 342.773C234.571 349.268 233.781 356.168 231.805 362.663C225.483 384.176 227.063 404.878 238.523 424.362C257.095 456.429 237.337 498.239 197.822 501.486C192.684 501.892 187.152 500.674 182.015 499.05C157.515 490.526 134.201 491.744 112.072 505.951C82.8304 524.217 44.8952 497.833 41.7339 470.636C40.9436 461.706 40.5485 453.182 43.7097 444.658C52.4032 421.521 48.8468 399.601 38.1775 378.088C33.0405 367.94 30.2743 356.98 31.4598 345.209C33.8308 322.883 53.9839 302.587 76.1127 300.964C84.4111 300.558 92.3142 301.37 99.8222 304.211C120.766 312.329 140.524 309.488 159.886 298.528C174.507 290.004 190.314 286.757 206.12 294.469C224.692 304.617 234.966 320.448 235.757 342.773Z" class="icon-color" />
12+</svg>
ui/src/assets/manifest.jsonnew file+14
@@ -0,0 +1,14 @@
1+{
2+ "name": "seek",
3+ "short_name": "seek",
4+ "icons": [
5+ {
6+ "src": "/apps/grid/android-chrome-512x512.png",
7+ "sizes": "512x512",
8+ "type": "image/png"
9+ }
10+ ],
11+ "theme_color": "#ffffff",
12+ "background_color": "#ffffff",
13+ "display": "standalone"
14+}
ui/src/assets/safari-pinned-tab.svgnew file+54
@@ -0,0 +1,54 @@
1+<?xml version="1.0" standalone="no"?>
2+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
3+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
4+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
5+ width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
6+ preserveAspectRatio="xMidYMid meet">
7+<metadata>
8+Created by potrace 1.14, written by Peter Selinger 2001-2017
9+</metadata>
10+<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
11+fill="#000000" stroke="none">
12+<path d="M5565 6989 c-16 -5 -39 -11 -50 -13 -54 -12 -116 -37 -230 -91 -219
13+-105 -335 -135 -495 -131 -63 2 -126 7 -140 10 -14 4 -36 9 -50 12 -14 3 -79
14+21 -145 41 -205 61 -361 54 -525 -23 -239 -113 -392 -356 -392 -625 0 -110 25
15+-201 107 -389 85 -197 116 -320 121 -480 3 -137 -12 -231 -60 -370 -15 -41
16+-30 -97 -33 -125 -8 -58 -8 -190 0 -255 27 -220 225 -440 475 -527 67 -24 92
17+-27 197 -27 109 0 127 3 189 28 37 16 100 47 140 70 174 103 316 141 521 140
18+146 0 208 -10 362 -58 171 -54 291 -54 449 -1 294 99 498 442 448 755 -4 25
19+-9 50 -10 55 -2 6 -7 24 -10 40 -4 17 -36 86 -71 153 -60 117 -113 253 -128
20+332 -4 19 -8 91 -10 160 -4 126 8 227 40 336 24 82 65 283 60 297 -2 6 -6 43
21+-10 81 -8 97 -22 150 -62 231 -44 90 -71 126 -148 200 -123 117 -255 175 -415
22+180 -52 2 -108 -1 -125 -6z"/>
23+<path d="M1445 6923 c-38 -8 -106 -31 -150 -52 -187 -90 -284 -214 -354 -455
24+-59 -201 -123 -321 -243 -451 -81 -88 -154 -143 -295 -222 -64 -35 -135 -79
25+-157 -96 -100 -76 -187 -210 -223 -347 -21 -80 -24 -308 -4 -390 22 -91 84
26+-209 146 -277 102 -112 188 -163 385 -228 307 -100 451 -229 620 -550 61 -115
27+94 -161 164 -228 52 -50 156 -117 181 -117 8 0 16 -4 19 -9 16 -26 274 -53
28+356 -37 14 3 37 7 53 10 71 12 165 55 237 109 122 90 201 216 265 420 51 165
29+96 258 172 359 86 114 212 216 358 290 147 75 226 139 292 238 36 53 80 162
30+89 216 3 22 8 42 10 46 3 4 7 53 9 109 10 221 -44 374 -180 512 -67 68 -167
31+136 -253 173 -31 14 -66 29 -77 33 -11 5 -47 19 -80 31 -164 59 -294 148 -377
32+257 -25 32 -97 137 -160 233 -131 199 -185 263 -272 324 -147 103 -335 138
33+-531 99z"/>
34+<path d="M5070 3824 c-177 -38 -296 -111 -399 -245 -36 -46 -88 -160 -122
35+-264 -103 -321 -254 -508 -534 -660 -184 -100 -292 -208 -352 -350 -113 -268
36+-56 -593 138 -785 81 -80 154 -122 300 -171 152 -51 233 -88 322 -147 139 -93
37+274 -254 346 -415 83 -185 208 -309 376 -372 84 -32 139 -40 260 -39 145 1
38+248 34 370 117 121 82 205 205 266 388 113 340 278 537 601 714 145 80 234
39+172 290 300 86 195 64 503 -49 694 -50 85 -141 172 -224 216 -37 19 -120 53
40+-184 76 -197 67 -303 129 -425 246 -92 87 -158 179 -230 323 -102 202 -207
41+301 -380 360 -82 28 -272 36 -370 14z"/>
42+<path d="M2395 3017 c-76 -22 -110 -37 -270 -119 -72 -38 -195 -82 -252 -93
43+-127 -22 -184 -24 -293 -10 -86 11 -114 17 -179 40 -132 47 -193 58 -317 57
44+-103 0 -176 -18 -268 -64 -142 -72 -258 -190 -325 -331 -95 -200 -84 -408 34
45+-666 95 -209 136 -366 136 -528 1 -142 -12 -213 -67 -380 -22 -66 -27 -97 -27
46+-198 -1 -66 2 -142 6 -169 29 -183 195 -384 394 -476 186 -87 369 -86 533 2
47+41 23 102 55 135 73 73 39 196 80 290 95 69 12 250 15 283 6 9 -3 38 -7 64
48+-11 26 -3 87 -17 135 -31 48 -14 113 -32 143 -41 211 -56 483 46 643 242 48
49+58 120 194 131 245 3 14 8 36 12 50 13 50 13 225 0 285 -19 81 -35 123 -94
50+240 -96 188 -122 287 -127 468 -2 115 7 188 40 317 52 202 68 337 50 423 -3
51+15 -7 39 -10 54 -8 38 -40 125 -58 159 -8 16 -24 45 -33 64 -28 53 -150 172
52+-229 222 -106 68 -172 89 -295 94 -88 3 -118 0 -185 -19z"/>
53+</g>
54+</svg>
ui/src/components/AppTile.tsxnew file+29
@@ -0,0 +1,29 @@
1+import { Charge } from '@urbit/api';
2+import React, { useState } from 'react';
3+
4+function normalizeUrbitColor(color: string): string {
5+ if (color.startsWith('#')) {
6+ return color;
7+ }
8+ return `#${color.slice(2).replace('.', '').toUpperCase()}`;
9+}
10+
11+export const AppTile = ({ image, color }: Charge) => {
12+ const [imageError, setImageError] = useState(false);
13+
14+ return (
15+ <div
16+ className="flex-none relative w-12 h-12 mr-3 rounded-lg bg-gray-200 overflow-hidden"
17+ style={{ backgroundColor: normalizeUrbitColor(color) }}
18+ >
19+ {image && !imageError && (
20+ <img
21+ className="absolute top-0 left-0 h-full w-full object-cover"
22+ src={image}
23+ alt=""
24+ onError={() => setImageError(true)}
25+ />
26+ )}
27+ </div>
28+ );
29+};
ui/src/env.d.tsnew file+7
@@ -0,0 +1,7 @@
1+interface ImportMetaEnv extends Readonly<Record<string, string | boolean | undefined>> {
2+ /* Add custom env properties here */
3+}
4+
5+interface ImportMeta {
6+ readonly env: ImportMetaEnv;
7+}
ui/src/index.cssnew file+3
@@ -0,0 +1,3 @@
1+@tailwind base;
2+@tailwind components;
3+@tailwind utilities;
ui/src/main.tsxnew file+11
@@ -0,0 +1,11 @@
1+import React from 'react';
2+import ReactDOM from 'react-dom';
3+import { App } from './app';
4+import './index.css';
5+
6+ReactDOM.render(
7+ <React.StrictMode>
8+ <App />
9+ </React.StrictMode>,
10+ document.getElementById('app')
11+);
ui/src/vite-env.d.tsnew file+1
@@ -0,0 +1 @@
1+/// <reference types="vite/client" />
ui/src/window.tsnew file+8
@@ -0,0 +1,8 @@
1+declare global {
2+ interface Window {
3+ ship: string;
4+ desk: string;
5+ }
6+}
7+
8+export {};
ui/tailwind.config.jsnew file+13
@@ -0,0 +1,13 @@
1+module.exports = {
2+ mode: 'jit',
3+ purge: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4+ darkMode: 'media', // or 'media' or 'class'
5+ theme: {
6+ extend: {}
7+ },
8+ screens: {},
9+ variants: {
10+ extend: {}
11+ },
12+ plugins: []
13+};
ui/tsconfig.jsonnew file+19
@@ -0,0 +1,19 @@
1+{
2+ "compilerOptions": {
3+ "target": "ESNext",
4+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
5+ "allowJs": false,
6+ "skipLibCheck": false,
7+ "esModuleInterop": false,
8+ "allowSyntheticDefaultImports": true,
9+ "strict": true,
10+ "forceConsistentCasingInFileNames": true,
11+ "module": "ESNext",
12+ "moduleResolution": "Node",
13+ "resolveJsonModule": true,
14+ "isolatedModules": true,
15+ "noEmit": true,
16+ "jsx": "react"
17+ },
18+ "include": ["./src"]
19+}
ui/vite.config.tsnew file+14
@@ -0,0 +1,14 @@
1+import { loadEnv, defineConfig } from 'vite';
2+import reactRefresh from '@vitejs/plugin-react-refresh';
3+import { urbitPlugin } from '@urbit/vite-plugin-urbit';
4+
5+// https://vitejs.dev/config/
6+export default ({ mode }) => {
7+ Object.assign(process.env, loadEnv(mode, process.cwd()));
8+ const SHIP_URL = process.env.SHIP_URL || process.env.VITE_SHIP_URL || 'http://localhost:8080';
9+ console.log(SHIP_URL);
10+
11+ return defineConfig({
12+ plugins: [urbitPlugin({ base: 'seek', target: SHIP_URL, secure: false }), reactRefresh()]
13+ });
14+};