├── .gitignore ├── LICENSE ├── README.md ├── chat-app ├── bare-desk │ ├── app │ │ └── hut.hoon │ ├── desk.bill │ ├── desk.docket-0 │ ├── desk.ship │ ├── mar │ │ └── hut │ │ │ ├── did.hoon │ │ │ └── do.hoon │ ├── sur │ │ └── hut.hoon │ └── sys.kelvin ├── full-desk │ ├── app │ │ └── hut.hoon │ ├── desk.bill │ ├── desk.docket-0 │ ├── desk.ship │ ├── lib │ │ ├── agentio.hoon │ │ ├── dbug.hoon │ │ ├── default-agent.hoon │ │ ├── docket.hoon │ │ ├── mip.hoon │ │ └── skeleton.hoon │ ├── mar │ │ ├── bill.hoon │ │ ├── docket-0.hoon │ │ ├── hoon.hoon │ │ ├── hut │ │ │ ├── did.hoon │ │ │ └── do.hoon │ │ ├── json.hoon │ │ ├── kelvin.hoon │ │ ├── mime.hoon │ │ ├── noun.hoon │ │ ├── ship.hoon │ │ ├── txt-diff.hoon │ │ └── txt.hoon │ ├── sur │ │ ├── docket.hoon │ │ ├── hut.hoon │ │ └── squad.hoon │ └── sys.kelvin └── ui │ ├── .gitignore │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── src │ ├── api.js │ ├── app.css │ ├── app.jsx │ ├── assets │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── manifest.json │ │ └── safari-pinned-tab.svg │ ├── components │ │ ├── ChatInput.jsx │ │ ├── ConnStatus.jsx │ │ ├── Huts.jsx │ │ ├── Messages.jsx │ │ ├── People.jsx │ │ └── SelectGid.jsx │ ├── const.js │ ├── lib.js │ └── main.jsx │ ├── tailwind.config.js │ └── vite.config.js ├── groups-app ├── bare-desk │ ├── app │ │ ├── squad.hoon │ │ └── squad │ │ │ └── index.hoon │ ├── desk.bill │ ├── desk.docket-0 │ ├── mar │ │ └── squad │ │ │ ├── did.hoon │ │ │ └── do.hoon │ ├── sur │ │ └── squad.hoon │ └── sys.kelvin └── full-desk │ ├── app │ ├── squad.hoon │ └── squad │ │ └── index.hoon │ ├── desk.bill │ ├── desk.docket-0 │ ├── lib │ ├── agentio.hoon │ ├── dbug.hoon │ ├── default-agent.hoon │ ├── docket.hoon │ └── skeleton.hoon │ ├── mar │ ├── bill.hoon │ ├── docket-0.hoon │ ├── hoon.hoon │ ├── json.hoon │ ├── kelvin.hoon │ ├── mime.hoon │ ├── noun.hoon │ ├── ship.hoon │ ├── squad │ │ ├── did.hoon │ │ └── do.hoon │ ├── txt-diff.hoon │ └── txt.hoon │ ├── sur │ ├── docket.hoon │ └── squad.hoon │ └── sys.kelvin ├── journal-app ├── bare-desk │ ├── app │ │ └── journal.hoon │ ├── desk.bill │ ├── desk.docket-0 │ ├── gen │ │ └── journal │ │ │ └── add.hoon │ ├── lib │ │ └── journal.hoon │ ├── mar │ │ └── journal │ │ │ ├── action.hoon │ │ │ └── update.hoon │ ├── sur │ │ └── journal.hoon │ └── sys.kelvin ├── full-desk │ ├── app │ │ └── journal.hoon │ ├── desk.bill │ ├── desk.docket-0 │ ├── gen │ │ └── journal │ │ │ └── add.hoon │ ├── lib │ │ ├── agentio.hoon │ │ ├── dbug.hoon │ │ ├── default-agent.hoon │ │ ├── docket.hoon │ │ ├── journal.hoon │ │ └── skeleton.hoon │ ├── mar │ │ ├── bill.hoon │ │ ├── docket-0.hoon │ │ ├── hoon.hoon │ │ ├── journal │ │ │ ├── action.hoon │ │ │ └── update.hoon │ │ ├── json.hoon │ │ ├── kelvin.hoon │ │ ├── mime.hoon │ │ ├── noun.hoon │ │ ├── txt-diff.hoon │ │ └── txt.hoon │ ├── sur │ │ ├── docket.hoon │ │ └── journal.hoon │ └── sys.kelvin └── ui │ ├── .gitignore │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── src │ ├── app.jsx │ ├── assets │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── manifest.json │ │ └── safari-pinned-tab.svg │ ├── index.css │ └── main.jsx │ └── vite.config.js └── voting-app ├── bare-desk ├── app │ ├── tally.hoon │ └── tally │ │ └── index.hoon ├── desk.bill ├── desk.docket-0 ├── lib │ └── ring.hoon ├── mar │ └── tally │ │ ├── action.hoon │ │ └── update.hoon ├── sur │ └── tally.hoon └── sys.kelvin └── full-desk ├── app ├── tally.hoon └── tally │ └── index.hoon ├── desk.bill ├── desk.docket-0 ├── lib ├── agentio.hoon ├── dbug.hoon ├── default-agent.hoon ├── docket.hoon ├── mip.hoon ├── ring.hoon └── skeleton.hoon ├── mar ├── bill.hoon ├── docket-0.hoon ├── hoon.hoon ├── json.hoon ├── kelvin.hoon ├── mime.hoon ├── noun.hoon ├── tally │ ├── action.hoon │ └── update.hoon ├── txt-diff.hoon └── txt.hoon ├── sur ├── docket.hoon ├── ring.hoon ├── squad.hoon └── tally.hoon └── sys.kelvin /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .tags 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 urbit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Urbit Developer Examples # 2 | 3 | This repo contains the source for the following examples presented in the 4 | [Urbit developer documentation][devdoc]: 5 | 6 | | Example Directory | Example Desk | Interface Type | 7 | |:------------------|:-------------|:---------------| 8 | | chat-app | %hut | React (JS) | 9 | | groups-app | %squad | Sail (Hoon) | 10 | | journal-app | %journal | React (JS) | 11 | | voting-app | %tally | Sail (Hoon) | 12 | 13 | In the documentation that follows, the following shorthands are used: 14 | 15 | - `/path/to/X/`: The path to directory `X` on your local machine. 16 | - `example-directory`: The directory of an example in the source tree of this 17 | repository (see the table above). 18 | - `example-desk`: The Urbit desk name of an example in this repository (see 19 | the table above). 20 | 21 | ## Install ## 22 | 23 | Each developer example is hosted on `~pocwet` and available for direct install 24 | via Urbit software distribution. To install the example on your ship, enter the 25 | following commands into your ship's `webterm` or `dojo`: 26 | 27 | ```bash 28 | |install ~pocwet %example-desk 29 | |mount %example-desk 30 | ``` 31 | 32 | You can then view the files associated with this example on your machine at the 33 | file path `/path/to/ship/example-desk`. Please note that this method **will only 34 | install Hoon files**; to view and experiment with React front-end files, please 35 | read on. 36 | 37 | ## Build ## 38 | 39 | ### First-time Setup ### 40 | 41 | To build one of these example from scratch (which is essential for React 42 | development), follow these instructions: 43 | 44 | 1. Download and extract the repo source code [from GitHub][gitsrc], e.g. 45 | at `/path/to/repo-source/`. 46 | 2. Follow the instructions for [creating a fake ship][fakeship], e.g. 47 | hosting it at `/path/to/fake-ship/`. 48 | 3. When booting up your fake ship, take note of the following line in 49 | the introductory digest: 50 | ``` 51 | http: web interface live on http://localhost:XYZ 52 | ``` 53 | The `XYZ` string on this line is port number your ship is using for its HTTP 54 | interface. Save this string for use in the subsequent steps. 55 | 4. In your fake ship's `dojo`, enter the following commands: 56 | ``` 57 | |new-desk %example-desk 58 | |mount %example-desk 59 | ``` 60 | 5. In a separate terminal session, enter the following commands: 61 | ```bash 62 | rm -rI /path/to/fake-ship/example-desk/* 63 | cp -RL /path/to/repo-source/example-directory/full-desk/* /path/to/fake-ship/example-desk/ 64 | ``` 65 | 6. Back in your fake ship's `dojo`, enter the following commands: 66 | ``` 67 | |commit %example-desk 68 | |install our %example-desk 69 | ``` 70 | 7. Again in your fake ship's `dojo`, run the following command and copy the 71 | result: 72 | ``` 73 | +code 74 | ``` 75 | This is your fake ship's password, which will be used for authentication 76 | from your web browser. 77 | 8. Open a web browser and navigate to the HTTP address discussed in step 3. 78 | 9. Paste the ship's password from step 7 into the form that appears and hit 79 | enter. 80 | 0. If the installation was successful, you should see a tile for the example 81 | on the home page that appears. 82 | 83 | If the example has a React interface, further follow these instructions to 84 | set up a locally-hosted front-end interface: 85 | 86 | 11. In a terminal session, enter the following commands (where `XYZ` is from 87 | step 3): 88 | ```bash 89 | cd /path/to/repo-source/example-directory/ui/ 90 | npm install 91 | echo "VITE_SHIP_URL=http://127.0.0.1:XYZ" >> .env.local 92 | npm run dev 93 | ``` 94 | The final command will generate a text digest containing a line of the form: 95 | ``` 96 | > Local: http://localhost:ABC/apps/example-desk/ 97 | ``` 98 | The web address listed here is hosting location for your local React 99 | interface. Save this string for use in the subsequent steps. 100 | 12. Open a web browser and navigate to the web address from the step 11. 101 | If the local hosting was successful, you should see the interface for the 102 | example in your browser. 103 | 104 | ### Editing and Rebuilding ### 105 | 106 | Once the base infrastructure for an example project is in place, making changes 107 | is very simple. 108 | 109 | For **React front-end development**, just make sure to run `npm run dev` in a 110 | terminal and to visit the output "local" address for testing; the page will 111 | automatically update as you edit your React files. 112 | 113 | For **Sail front-end development and back-end development**, the process is only 114 | slightly more complicated: 115 | 116 | 1. If you're editing the files in-place (i.e. in 117 | `/path/to/fake-ship/example-desk/`), you can skip this step. If you're 118 | editing files from the source tree 119 | (i.e. in `/path/to/repo-source/example-directory/full-desk/`), you'll need 120 | to copy the files to your ship with the following terminal commands: 121 | ```bash 122 | rm -rI /path/to/fake-ship/example-desk/* 123 | cp -RL /path/to/repo-source/example-directory/full-desk/* /path/to/fake-ship/example-desk/ 124 | ``` 125 | 2. From within your fake ship's `dojo`, enter one of the following command 126 | sequences based on your changes: 127 | - If you didn't make any changes to the example app's data model: 128 | ``` 129 | |commit %example-desk 130 | ``` 131 | - If you did make changes to the example app's data model (e.g. via `/sur` 132 | file changes, app `state` changes, etc.): 133 | ``` 134 | |nuke %example-desk 135 | |commit %example-desk 136 | ``` 137 | 138 | 139 | [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 140 | [devdoc]: https://developers.urbit.org 141 | [gitsrc]: https://github.com/urbit/docs-examples/archive/refs/heads/main.zip 142 | [fakeship]: https://developers.urbit.org/guides/core/environment#creating-a-fake-ship 143 | -------------------------------------------------------------------------------- /chat-app/bare-desk/desk.bill: -------------------------------------------------------------------------------- 1 | :~ %hut 2 | == 3 | -------------------------------------------------------------------------------- /chat-app/bare-desk/desk.docket-0: -------------------------------------------------------------------------------- 1 | :~ 2 | title+'Hut' 3 | info+'A simple chat app.' 4 | color+0x7c.afc2 5 | version+[0 1 1] 6 | website+'https://urbit.org' 7 | license+'MIT' 8 | base+'hut' 9 | :+ %glob-http 10 | 'https://m.tinnus-napbus.xyz/pub/hut-glob-0v2.5dmm5.nhie8.81nnk.9dm67.6t1ai.glob' 11 | 0v2.5dmm5.nhie8.81nnk.9dm67.6t1ai 12 | == 13 | -------------------------------------------------------------------------------- /chat-app/bare-desk/desk.ship: -------------------------------------------------------------------------------- 1 | ~pocwet 2 | -------------------------------------------------------------------------------- /chat-app/bare-desk/mar/hut/did.hoon: -------------------------------------------------------------------------------- 1 | /- *hut 2 | |_ u=hut-upd 3 | ++ grow 4 | |% 5 | ++ noun u 6 | ++ json 7 | =, enjs:format 8 | |^ ^- ^json 9 | ?- -.u 10 | %new 11 | %+ frond 'new' 12 | (pairs ~[['hut' (en-hut hut.u)] ['msgs' (en-msgs msgs.u)]]) 13 | :: 14 | %post 15 | %+ frond 'post' 16 | (pairs ~[['hut' (en-hut hut.u)] ['msg' (en-msg msg.u)]]) 17 | :: 18 | %join 19 | %+ frond 'join' 20 | (pairs ~[['gid' (en-gid gid.u)] ['who' s+(scot %p who.u)]]) 21 | :: 22 | %quit 23 | %+ frond 'quit' 24 | (pairs ~[['gid' (en-gid gid.u)] ['who' s+(scot %p who.u)]]) 25 | :: 26 | %del 27 | (frond 'del' (frond 'hut' (en-hut hut.u))) 28 | :: 29 | %init 30 | %+ frond 'init' 31 | %- pairs 32 | :~ ['huts' (en-huts huts.u)] 33 | ['msgJar' (en-msg-jar msg-jar.u)] 34 | ['joined' (en-joined joined.u)] 35 | == 36 | :: 37 | %init-all 38 | %+ frond 'initAll' 39 | %- pairs 40 | :~ ['huts' (en-huts huts.u)] 41 | ['msgJar' (en-msg-jar msg-jar.u)] 42 | ['joined' (en-joined joined.u)] 43 | == 44 | == 45 | ++ en-joined 46 | |= =joined 47 | ^- ^json 48 | :- %a 49 | %+ turn ~(tap by joined) 50 | |= [=gid =ppl] 51 | %- pairs 52 | :~ ['gid' (en-gid gid)] 53 | :- 'ppl' 54 | a+(sort (turn ~(tap in ppl) |=(=@p s+(scot %p p))) aor) 55 | == 56 | ++ en-msg-jar 57 | |= =msg-jar 58 | ^- ^json 59 | :- %a 60 | %+ turn ~(tap by msg-jar) 61 | |= [=hut =msgs] 62 | (pairs ~[['hut' (en-hut hut)] ['msgs' (en-msgs msgs)]]) 63 | ++ en-huts 64 | |= =huts 65 | ^- ^json 66 | :- %a 67 | %+ turn ~(tap by huts) 68 | |= [=gid names=(set name)] 69 | %- pairs 70 | :~ ['gid' (en-gid gid)] 71 | ['names' a+(turn (sort ~(tap in names) aor) (lead %s))] 72 | == 73 | ++ en-msgs |=(=msgs `^json`a+(turn (flop msgs) en-msg)) 74 | ++ en-msg 75 | |= =msg 76 | ^- ^json 77 | (pairs ~[['who' s+(scot %p who.msg)] ['what' s+what.msg]]) 78 | ++ en-hut 79 | |= =hut 80 | ^- ^json 81 | (pairs ~[['gid' (en-gid gid.hut)] ['name' s+name.hut]]) 82 | ++ en-gid 83 | |= =gid 84 | ^- ^json 85 | (pairs ~[['host' s+(scot %p host.gid)] ['name' s+name.gid]]) 86 | -- 87 | -- 88 | ++ grab 89 | |% 90 | ++ noun hut-upd 91 | -- 92 | ++ grad %noun 93 | -- 94 | -------------------------------------------------------------------------------- /chat-app/bare-desk/mar/hut/do.hoon: -------------------------------------------------------------------------------- 1 | /- *hut 2 | |_ a=hut-act 3 | ++ grow 4 | |% 5 | ++ noun a 6 | -- 7 | ++ grab 8 | |% 9 | ++ noun hut-act 10 | ++ json 11 | =, dejs:format 12 | |= jon=json 13 | |^ ^- hut-act 14 | %. jon 15 | %- of 16 | :~ new+(ot ~[hut+de-hut msgs+(ar de-msg)]) 17 | post+(ot ~[hut+de-hut msg+de-msg]) 18 | join+(ot ~[gid+de-gid who+(se %p)]) 19 | quit+(ot ~[gid+de-gid who+(se %p)]) 20 | del+(ot ~[hut+de-hut]) 21 | == 22 | ++ de-msg (ot ~[who+(se %p) what+so]) 23 | ++ de-hut (ot ~[gid+de-gid name+(se %tas)]) 24 | ++ de-gid (ot ~[host+(se %p) name+(se %tas)]) 25 | -- 26 | -- 27 | ++ grad %noun 28 | -- 29 | -------------------------------------------------------------------------------- /chat-app/bare-desk/sur/hut.hoon: -------------------------------------------------------------------------------- 1 | /- *squad 2 | |% 3 | +$ msg [who=@p what=@t] 4 | +$ msgs (list msg) 5 | +$ name @tas 6 | +$ hut [=gid =name] 7 | :: 8 | +$ huts (jug gid name) 9 | +$ msg-jar (jar hut msg) 10 | +$ joined (jug gid @p) 11 | :: 12 | +$ hut-act 13 | $% [%new =hut =msgs] 14 | [%post =hut =msg] 15 | [%join =gid who=@p] 16 | [%quit =gid who=@p] 17 | [%del =hut] 18 | == 19 | +$ hut-upd 20 | $% [%init =huts =msg-jar =joined] 21 | [%init-all =huts =msg-jar =joined] 22 | hut-act 23 | == 24 | -- 25 | -------------------------------------------------------------------------------- /chat-app/bare-desk/sys.kelvin: -------------------------------------------------------------------------------- 1 | [%zuse 410] 2 | [%zuse 411] 3 | [%zuse 412] 4 | [%zuse 413] 5 | -------------------------------------------------------------------------------- /chat-app/full-desk/app/hut.hoon: -------------------------------------------------------------------------------- 1 | ../../bare-desk/app/hut.hoon -------------------------------------------------------------------------------- /chat-app/full-desk/desk.bill: -------------------------------------------------------------------------------- 1 | ../bare-desk/desk.bill -------------------------------------------------------------------------------- /chat-app/full-desk/desk.docket-0: -------------------------------------------------------------------------------- 1 | ../bare-desk/desk.docket-0 -------------------------------------------------------------------------------- /chat-app/full-desk/desk.ship: -------------------------------------------------------------------------------- 1 | ../bare-desk/desk.ship -------------------------------------------------------------------------------- /chat-app/full-desk/lib/agentio.hoon: -------------------------------------------------------------------------------- 1 | => 2 | |% 3 | ++ card card:agent:gall 4 | -- 5 | :: 6 | |_ =bowl:gall 7 | ++ scry 8 | |= [desk=@tas =path] 9 | %+ weld 10 | /(scot %p our.bowl)/[desk]/(scot %da now.bowl) 11 | path 12 | :: 13 | ++ pass 14 | |_ =wire 15 | ++ poke 16 | |= [=dock =cage] 17 | [%pass wire %agent dock %poke cage] 18 | :: 19 | ++ poke-our 20 | |= [app=term =cage] 21 | ^- card 22 | (poke [our.bowl app] cage) 23 | :: 24 | ++ poke-self 25 | |= =cage 26 | ^- card 27 | (poke-our dap.bowl cage) 28 | :: 29 | ++ arvo 30 | |= =note-arvo 31 | ^- card 32 | [%pass wire %arvo note-arvo] 33 | :: 34 | ++ watch 35 | |= [=dock =path] 36 | [%pass (watch-wire path) %agent dock %watch path] 37 | :: 38 | ++ watch-our 39 | |= [app=term =path] 40 | (watch [our.bowl app] path) 41 | :: 42 | ++ watch-wire 43 | |= =path 44 | ^+ wire 45 | ?. ?=(~ wire) 46 | wire 47 | agentio-watch+path 48 | :: 49 | ++ leave 50 | |= =dock 51 | [%pass wire %agent dock %leave ~] 52 | :: 53 | ++ leave-our 54 | |= app=term 55 | (leave our.bowl app) 56 | :: 57 | ++ leave-path 58 | |= [=dock =path] 59 | =. wire 60 | (watch-wire path) 61 | (leave dock) 62 | :: 63 | ++ wait 64 | |= p=@da 65 | (arvo %b %wait p) 66 | :: 67 | ++ rest 68 | |= p=@da 69 | (arvo %b %rest p) 70 | :: 71 | ++ warp 72 | |= [wer=ship =riff:clay] 73 | (arvo %c %warp wer riff) 74 | :: 75 | ++ warp-our 76 | |= =riff:clay 77 | (warp our.bowl riff) 78 | :: 79 | :: right here, right now 80 | ++ warp-slim 81 | |= [genre=?(%sing %next) =care:clay =path] 82 | =/ =mood:clay 83 | [care r.byk.bowl path] 84 | =/ =rave:clay 85 | ?:(?=(%sing genre) [genre mood] [genre mood]) 86 | (warp-our q.byk.bowl `rave) 87 | :: 88 | ++ tire 89 | (arvo %c %tire `~) 90 | :: 91 | ++ connect 92 | |= [=binding:eyre app=term] 93 | (arvo %e %connect binding app) 94 | -- 95 | :: 96 | ++ fact-kick 97 | |= [=path =cage] 98 | ^- (list card) 99 | :~ (fact cage ~[path]) 100 | (kick ~[path]) 101 | == 102 | :: 103 | ++ fact-init 104 | |= =cage 105 | ^- card 106 | [%give %fact ~ cage] 107 | :: 108 | ++ fact-init-kick 109 | |= =cage 110 | ^- (list card) 111 | :~ (fact cage ~) 112 | (kick ~) 113 | == 114 | :: 115 | ++ fact 116 | |= [=cage paths=(list path)] 117 | ^- card 118 | [%give %fact paths cage] 119 | :: 120 | ++ fact-all 121 | |= =cage 122 | ^- (unit card) 123 | =/ paths=(set path) 124 | %- ~(gas in *(set path)) 125 | %+ turn ~(tap by sup.bowl) 126 | |=([duct ship =path] path) 127 | ?: =(~ paths) ~ 128 | `(fact cage ~(tap in paths)) 129 | :: 130 | ++ kick 131 | |= paths=(list path) 132 | [%give %kick paths ~] 133 | :: 134 | ++ kick-only 135 | |= [=ship paths=(list path)] 136 | [%give %kick paths `ship] 137 | -- 138 | -------------------------------------------------------------------------------- /chat-app/full-desk/lib/dbug.hoon: -------------------------------------------------------------------------------- 1 | :: dbug: agent wrapper for generic debugging tools 2 | :: 3 | :: usage: %-(agent:dbug your-agent) 4 | :: 5 | |% 6 | +$ poke 7 | $% [%bowl ~] 8 | [%state grab=cord] 9 | [%incoming =about] 10 | [%outgoing =about] 11 | == 12 | :: 13 | +$ about 14 | $@ ~ 15 | $% [%ship =ship] 16 | [%path =path] 17 | [%wire =wire] 18 | [%term =term] 19 | == 20 | :: 21 | ++ agent 22 | |= =agent:gall 23 | ^- agent:gall 24 | !. 25 | |_ =bowl:gall 26 | +* this . 27 | ag ~(. agent bowl) 28 | :: 29 | ++ on-poke 30 | |= [=mark =vase] 31 | ^- (quip card:agent:gall agent:gall) 32 | ?. ?=(%dbug mark) 33 | =^ cards agent (on-poke:ag mark vase) 34 | [cards this] 35 | =/ dbug 36 | !<(poke vase) 37 | =; =tang 38 | ((%*(. slog pri 1) tang) [~ this]) 39 | ?- -.dbug 40 | %bowl [(sell !>(bowl))]~ 41 | :: 42 | %state 43 | =? grab.dbug =('' grab.dbug) '-' 44 | =; product=^vase 45 | [(sell product)]~ 46 | =/ state=^vase 47 | :: if the underlying app has implemented a /dbug/state scry endpoint, 48 | :: use that vase in place of +on-save's. 49 | :: 50 | =/ result=(each ^vase tang) 51 | (mule |.(q:(need (need (on-peek:ag /x/dbug/state))))) 52 | ?:(?=(%& -.result) p.result on-save:ag) 53 | %+ slap 54 | (slop state !>([bowl=bowl ..zuse])) 55 | (ream grab.dbug) 56 | :: 57 | %incoming 58 | =; =tang 59 | ?^ tang tang 60 | [%leaf "no matching subscriptions"]~ 61 | %+ murn 62 | %+ sort ~(tap by sup.bowl) 63 | |= [[* a=[=ship =path]] [* b=[=ship =path]]] 64 | (aor [path ship]:a [path ship]:b) 65 | |= [=duct [=ship =path]] 66 | ^- (unit tank) 67 | =; relevant=? 68 | ?. relevant ~ 69 | `>[path=path from=ship duct=duct]< 70 | ?: ?=(~ about.dbug) & 71 | ?- -.about.dbug 72 | %ship =(ship ship.about.dbug) 73 | %path ?=(^ (find path.about.dbug path)) 74 | %wire %+ lien duct 75 | |=(=wire ?=(^ (find wire.about.dbug wire))) 76 | %term !! 77 | == 78 | :: 79 | %outgoing 80 | =; =tang 81 | ?^ tang tang 82 | [%leaf "no matching subscriptions"]~ 83 | %+ murn 84 | %+ sort ~(tap by wex.bowl) 85 | |= [[[a=wire *] *] [[b=wire *] *]] 86 | (aor a b) 87 | |= [[=wire =ship =term] [acked=? =path]] 88 | ^- (unit tank) 89 | =; relevant=? 90 | ?. relevant ~ 91 | `>[wire=wire agnt=[ship term] path=path ackd=acked]< 92 | ?: ?=(~ about.dbug) & 93 | ?- -.about.dbug 94 | %ship =(ship ship.about.dbug) 95 | %path ?=(^ (find path.about.dbug path)) 96 | %wire ?=(^ (find wire.about.dbug wire)) 97 | %term =(term term.about.dbug) 98 | == 99 | == 100 | :: 101 | ++ on-peek 102 | |= =path 103 | ^- (unit (unit cage)) 104 | ?. ?=([@ %dbug *] path) 105 | (on-peek:ag path) 106 | ?+ path [~ ~] 107 | [%u %dbug ~] ``noun+!>(&) 108 | [%x %dbug %state ~] ``noun+!>(on-save:ag) 109 | [%x %dbug %subscriptions ~] ``noun+!>([wex sup]:bowl) 110 | == 111 | :: 112 | ++ on-init 113 | ^- (quip card:agent:gall agent:gall) 114 | =^ cards agent on-init:ag 115 | [cards this] 116 | :: 117 | ++ on-save on-save:ag 118 | :: 119 | ++ on-load 120 | |= old-state=vase 121 | ^- (quip card:agent:gall agent:gall) 122 | =^ cards agent (on-load:ag old-state) 123 | [cards this] 124 | :: 125 | ++ on-watch 126 | |= =path 127 | ^- (quip card:agent:gall agent:gall) 128 | =^ cards agent (on-watch:ag path) 129 | [cards this] 130 | :: 131 | ++ on-leave 132 | |= =path 133 | ^- (quip card:agent:gall agent:gall) 134 | =^ cards agent (on-leave:ag path) 135 | [cards this] 136 | :: 137 | ++ on-agent 138 | |= [=wire =sign:agent:gall] 139 | ^- (quip card:agent:gall agent:gall) 140 | =^ cards agent (on-agent:ag wire sign) 141 | [cards this] 142 | :: 143 | ++ on-arvo 144 | |= [=wire =sign-arvo] 145 | ^- (quip card:agent:gall agent:gall) 146 | =^ cards agent (on-arvo:ag wire sign-arvo) 147 | [cards this] 148 | :: 149 | ++ on-fail 150 | |= [=term =tang] 151 | ^- (quip card:agent:gall agent:gall) 152 | =^ cards agent (on-fail:ag term tang) 153 | [cards this] 154 | -- 155 | -- 156 | -------------------------------------------------------------------------------- /chat-app/full-desk/lib/default-agent.hoon: -------------------------------------------------------------------------------- 1 | /+ skeleton 2 | |* [agent=* help=*] 3 | ?: ?=(%& help) 4 | ~| %default-agent-helpfully-crashing 5 | skeleton 6 | |_ =bowl:gall 7 | ++ on-init 8 | `agent 9 | :: 10 | ++ on-save 11 | !>(~) 12 | :: 13 | ++ on-load 14 | |= old-state=vase 15 | `agent 16 | :: 17 | ++ on-poke 18 | |= =cage 19 | ~| "unexpected poke to {} with mark {}" 20 | !! 21 | :: 22 | ++ on-watch 23 | |= =path 24 | ~| "unexpected subscription to {} on path {}" 25 | !! 26 | :: 27 | ++ on-leave 28 | |= path 29 | `agent 30 | :: 31 | ++ on-peek 32 | |= =path 33 | ~| "unexpected scry into {} on path {}" 34 | !! 35 | :: 36 | ++ on-agent 37 | |= [=wire =sign:agent:gall] 38 | ^- (quip card:agent:gall _agent) 39 | ?- -.sign 40 | %poke-ack 41 | ?~ p.sign 42 | `agent 43 | %- (slog leaf+"poke failed from {} on wire {}" u.p.sign) 44 | `agent 45 | :: 46 | %watch-ack 47 | ?~ p.sign 48 | `agent 49 | =/ =tank leaf+"subscribe failed from {} on wire {}" 50 | %- (slog tank u.p.sign) 51 | `agent 52 | :: 53 | %kick `agent 54 | %fact 55 | ~| "unexpected subscription update to {} on wire {}" 56 | ~| "with mark {}" 57 | !! 58 | == 59 | :: 60 | ++ on-arvo 61 | |= [=wire =sign-arvo] 62 | ~| "unexpected system response {<-.sign-arvo>} to {} on wire {}" 63 | !! 64 | :: 65 | ++ on-fail 66 | |= [=term =tang] 67 | %- (slog leaf+"error in {}" >term< tang) 68 | `agent 69 | -- 70 | -------------------------------------------------------------------------------- /chat-app/full-desk/lib/docket.hoon: -------------------------------------------------------------------------------- 1 | /- *docket 2 | |% 3 | :: 4 | ++ mime 5 | |% 6 | +$ draft 7 | $: title=(unit @t) 8 | info=(unit @t) 9 | color=(unit @ux) 10 | glob-http=(unit [=url hash=@uvH]) 11 | glob-ames=(unit [=ship hash=@uvH]) 12 | base=(unit term) 13 | site=(unit path) 14 | image=(unit url) 15 | version=(unit version) 16 | website=(unit url) 17 | license=(unit cord) 18 | == 19 | :: 20 | ++ finalize 21 | |= =draft 22 | ^- (unit docket) 23 | ?~ title.draft ~ 24 | ?~ info.draft ~ 25 | ?~ color.draft ~ 26 | ?~ version.draft ~ 27 | ?~ website.draft ~ 28 | ?~ license.draft ~ 29 | =/ href=(unit href) 30 | ?^ site.draft `[%site u.site.draft] 31 | ?~ base.draft ~ 32 | ?^ glob-http.draft 33 | `[%glob u.base hash.u.glob-http %http url.u.glob-http]:draft 34 | ?~ glob-ames.draft 35 | ~ 36 | `[%glob u.base hash.u.glob-ames %ames ship.u.glob-ames]:draft 37 | ?~ href ~ 38 | =, draft 39 | :- ~ 40 | :* %1 41 | u.title 42 | u.info 43 | u.color 44 | u.href 45 | image 46 | u.version 47 | u.website 48 | u.license 49 | == 50 | :: 51 | ++ from-clauses 52 | =| =draft 53 | |= cls=(list clause) 54 | ^- (unit docket) 55 | =* loop $ 56 | ?~ cls (finalize draft) 57 | =* clause i.cls 58 | =. draft 59 | ?- -.clause 60 | %title draft(title `title.clause) 61 | %info draft(info `info.clause) 62 | %color draft(color `color.clause) 63 | %glob-http draft(glob-http `[url hash]:clause) 64 | %glob-ames draft(glob-ames `[ship hash]:clause) 65 | %base draft(base `base.clause) 66 | %site draft(site `path.clause) 67 | %image draft(image `url.clause) 68 | %version draft(version `version.clause) 69 | %website draft(website `website.clause) 70 | %license draft(license `license.clause) 71 | == 72 | loop(cls t.cls) 73 | :: 74 | ++ to-clauses 75 | |= d=docket 76 | ^- (list clause) 77 | %- zing 78 | :~ :~ title+title.d 79 | info+info.d 80 | color+color.d 81 | version+version.d 82 | website+website.d 83 | license+license.d 84 | == 85 | ?~ image.d ~ ~[image+u.image.d] 86 | ?: ?=(%site -.href.d) ~[site+path.href.d] 87 | =/ ref=glob-reference glob-reference.href.d 88 | :~ base+base.href.d 89 | ?- -.location.ref 90 | %http [%glob-http url.location.ref hash.ref] 91 | %ames [%glob-ames ship.location.ref hash.ref] 92 | == == == 93 | :: 94 | ++ spit-clause 95 | |= =clause 96 | ^- tape 97 | %+ weld " {(trip -.clause)}+" 98 | ?+ -.clause "'{(trip +.clause)}'" 99 | %color (scow %ux color.clause) 100 | %site (spud path.clause) 101 | :: 102 | %glob-http 103 | "['{(trip url.clause)}' {(scow %uv hash.clause)}]" 104 | :: 105 | %glob-ames 106 | "[{(scow %p ship.clause)} {(scow %uv hash.clause)}]" 107 | :: 108 | %version 109 | =, version.clause 110 | "[{(scow %ud major)} {(scow %ud minor)} {(scow %ud patch)}]" 111 | == 112 | :: 113 | ++ spit-docket 114 | |= dock=docket 115 | ^- tape 116 | ;: welp 117 | ":~\0a" 118 | `tape`(zing (join "\0a" (turn (to-clauses dock) spit-clause))) 119 | "\0a==" 120 | == 121 | -- 122 | :: 123 | ++ enjs 124 | =, enjs:format 125 | |% 126 | :: 127 | ++ charge-update 128 | |= u=^charge-update 129 | ^- json 130 | %+ frond -.u 131 | ^- json 132 | ?- -.u 133 | %del-charge s+desk.u 134 | :: 135 | %initial 136 | %- pairs 137 | %+ turn ~(tap by initial.u) 138 | |=([=desk c=^charge] [desk (charge c)]) 139 | :: 140 | %add-charge 141 | %- pairs 142 | :~ desk+s+desk.u 143 | charge+(charge charge.u) 144 | == 145 | == 146 | :: 147 | ++ num 148 | |= a=@u 149 | ^- ^tape 150 | =/ p=json (numb a) 151 | ?> ?=(%n -.p) 152 | (trip p.p) 153 | :: 154 | ++ version 155 | |= v=^version 156 | ^- json 157 | :- %s 158 | %- crip 159 | "{(num major.v)}.{(num minor.v)}.{(num patch.v)}" 160 | :: 161 | ++ merge 162 | |= [a=json b=json] 163 | ^- json 164 | ?> &(?=(%o -.a) ?=(%o -.b)) 165 | [%o (~(uni by p.a) p.b)] 166 | :: 167 | ++ href 168 | |= h=^href 169 | %+ frond -.h 170 | ?- -.h 171 | %site s+(spat path.h) 172 | %glob 173 | %- pairs 174 | :~ base+s+base.h 175 | glob-reference+(glob-reference glob-reference.h) 176 | == 177 | == 178 | :: 179 | ++ glob-reference 180 | |= ref=^glob-reference 181 | %- pairs 182 | :~ hash+s+(scot %uv hash.ref) 183 | location+(glob-location location.ref) 184 | == 185 | :: 186 | ++ glob-location 187 | |= loc=^glob-location 188 | ^- json 189 | %+ frond -.loc 190 | ?- -.loc 191 | %http s+url.loc 192 | %ames s+(scot %p ship.loc) 193 | == 194 | :: 195 | ++ charge 196 | |= c=^charge 197 | %+ merge (docket docket.c) 198 | %- pairs 199 | :~ chad+(chad chad.c) 200 | == 201 | :: 202 | ++ docket 203 | |= d=^docket 204 | ^- json 205 | %- pairs 206 | :~ title+s+title.d 207 | info+s+info.d 208 | color+s+(scot %ux color.d) 209 | href+(href href.d) 210 | image+?~(image.d ~ s+u.image.d) 211 | version+(version version.d) 212 | license+s+license.d 213 | website+s+website.d 214 | == 215 | :: 216 | ++ chad 217 | |= c=^chad 218 | %+ frond -.c 219 | ?+ -.c ~ 220 | %hung s+err.c 221 | == 222 | -- 223 | -- 224 | -------------------------------------------------------------------------------- /chat-app/full-desk/lib/mip.hoon: -------------------------------------------------------------------------------- 1 | |% 2 | ++ mip :: map of maps 3 | |$ [kex key value] 4 | (map kex (map key value)) 5 | :: 6 | ++ bi :: mip engine 7 | =| a=(map * (map)) 8 | |@ 9 | ++ del 10 | |* [b=* c=*] 11 | =+ d=(~(gut by a) b ~) 12 | =+ e=(~(del by d) c) 13 | ?~ e 14 | (~(del by a) b) 15 | (~(put by a) b e) 16 | :: 17 | ++ get 18 | |* [b=* c=*] 19 | => .(b `_?>(?=(^ a) p.n.a)`b, c `_?>(?=(^ a) ?>(?=(^ q.n.a) p.n.q.n.a))`c) 20 | ^- (unit _?>(?=(^ a) ?>(?=(^ q.n.a) q.n.q.n.a))) 21 | (~(get by (~(gut by a) b ~)) c) 22 | :: 23 | ++ got 24 | |* [b=* c=*] 25 | (need (get b c)) 26 | :: 27 | ++ gut 28 | |* [b=* c=* d=*] 29 | (~(gut by (~(gut by a) b ~)) c d) 30 | :: 31 | ++ has 32 | |* [b=* c=*] 33 | !=(~ (get b c)) 34 | :: 35 | ++ key 36 | |* b=* 37 | ~(key by (~(gut by a) b ~)) 38 | :: 39 | ++ put 40 | |* [b=* c=* d=*] 41 | %+ ~(put by a) b 42 | %. [c d] 43 | %~ put by 44 | (~(gut by a) b ~) 45 | :: 46 | ++ tap 47 | ::NOTE naive turn-based implementation find-errors ): 48 | =< $ 49 | =+ b=`_?>(?=(^ a) *(list [x=_p.n.a _?>(?=(^ q.n.a) [y=p v=q]:n.q.n.a)]))`~ 50 | |. ^+ b 51 | ?~ a 52 | b 53 | $(a r.a, b (welp (turn ~(tap by q.n.a) (lead p.n.a)) $(a l.a))) 54 | -- 55 | -- 56 | -------------------------------------------------------------------------------- /chat-app/full-desk/lib/skeleton.hoon: -------------------------------------------------------------------------------- 1 | :: Similar to default-agent except crashes everywhere 2 | ^- agent:gall 3 | |_ bowl:gall 4 | ++ on-init 5 | ^- (quip card:agent:gall agent:gall) 6 | !! 7 | :: 8 | ++ on-save 9 | ^- vase 10 | !! 11 | :: 12 | ++ on-load 13 | |~ old-state=vase 14 | ^- (quip card:agent:gall agent:gall) 15 | !! 16 | :: 17 | ++ on-poke 18 | |~ in-poke-data=cage 19 | ^- (quip card:agent:gall agent:gall) 20 | !! 21 | :: 22 | ++ on-watch 23 | |~ path 24 | ^- (quip card:agent:gall agent:gall) 25 | !! 26 | :: 27 | ++ on-leave 28 | |~ path 29 | ^- (quip card:agent:gall agent:gall) 30 | !! 31 | :: 32 | ++ on-peek 33 | |~ path 34 | ^- (unit (unit cage)) 35 | !! 36 | :: 37 | ++ on-agent 38 | |~ [wire sign:agent:gall] 39 | ^- (quip card:agent:gall agent:gall) 40 | !! 41 | :: 42 | ++ on-arvo 43 | |~ [wire =sign-arvo] 44 | ^- (quip card:agent:gall agent:gall) 45 | !! 46 | :: 47 | ++ on-fail 48 | |~ [term tang] 49 | ^- (quip card:agent:gall agent:gall) 50 | !! 51 | -- 52 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/bill.hoon: -------------------------------------------------------------------------------- 1 | |_ bil=(list dude:gall) 2 | ++ grow 3 | |% 4 | ++ mime `^mime`[/text/x-bill (as-octs:mimes:html hoon)] 5 | ++ noun bil 6 | ++ hoon 7 | ^- @t 8 | |^ (crip (of-wall:format (wrap-lines (spit-duz bil)))) 9 | :: 10 | ++ wrap-lines 11 | |= taz=wall 12 | ^- wall 13 | ?~ taz ["~"]~ 14 | :- (weld ":~ " i.taz) 15 | %- snoc :_ "==" 16 | (turn t.taz |=(t=tape (weld " " t))) 17 | :: 18 | ++ spit-duz 19 | |= duz=(list dude:gall) 20 | ^- wall 21 | (turn duz |=(=dude:gall ['%' (trip dude)])) 22 | -- 23 | ++ txt (to-wain:format hoon) 24 | -- 25 | ++ grab 26 | |% 27 | ++ noun (list dude:gall) 28 | ++ mime 29 | |= [=mite len=@ud tex=@] 30 | ~_ tex 31 | !<((list dude:gall) (slap !>(~) (ream tex))) 32 | -- 33 | ++ grad %noun 34 | -- 35 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/docket-0.hoon: -------------------------------------------------------------------------------- 1 | /+ dock=docket 2 | |_ =docket:dock 3 | ++ grow 4 | |% 5 | ++ mime 6 | ^- ^mime 7 | [/text/x-docket (as-octt:mimes:html (spit-docket:mime:dock docket))] 8 | ++ noun docket 9 | ++ json (docket:enjs:dock docket) 10 | -- 11 | ++ grab 12 | |% 13 | :: 14 | ++ mime 15 | |= [=mite len=@ud tex=@] 16 | ^- docket:dock 17 | %- need 18 | %- from-clauses:mime:dock 19 | !<((list clause:dock) (slap !>(~) (ream tex))) 20 | 21 | :: 22 | ++ noun docket:dock 23 | -- 24 | ++ grad %noun 25 | -- 26 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/hoon.hoon: -------------------------------------------------------------------------------- 1 | :::: /hoon/hoon/mar 2 | :: 3 | /? 310 4 | :: 5 | =, eyre 6 | |_ own=@t 7 | :: 8 | ++ grow :: convert to 9 | |% 10 | ++ mime `^mime`[/text/x-hoon (as-octs:mimes:html own)] :: convert to %mime 11 | ++ hymn 12 | ;html 13 | ;head 14 | ;title:"Source" 15 | ;script@"//cdnjs.cloudflare.com/ajax/libs/codemirror/4.3.0/codemirror.js"; 16 | ;script@"/lib/syntax/hoon.js"; 17 | ;link(rel "stylesheet", href "//cdnjs.cloudflare.com/ajax/libs/". 18 | "codemirror/4.3.0/codemirror.min.css"); 19 | ;link/"/lib/syntax/codemirror.css"(rel "stylesheet"); 20 | == 21 | ;body 22 | ;textarea#src:"{(trip own)}" 23 | ;script:'CodeMirror.fromTextArea(src, {lineNumbers:true, readOnly:true})' 24 | == 25 | == 26 | ++ txt 27 | (to-wain:format own) 28 | -- 29 | ++ grab 30 | |% :: convert from 31 | ++ mime |=([p=mite q=octs] q.q) 32 | ++ noun @t :: clam from %noun 33 | ++ txt of-wain:format 34 | -- 35 | ++ grad %txt 36 | -- 37 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/hut/did.hoon: -------------------------------------------------------------------------------- 1 | ../../../bare-desk/mar/hut/did.hoon -------------------------------------------------------------------------------- /chat-app/full-desk/mar/hut/do.hoon: -------------------------------------------------------------------------------- 1 | ../../../bare-desk/mar/hut/do.hoon -------------------------------------------------------------------------------- /chat-app/full-desk/mar/json.hoon: -------------------------------------------------------------------------------- 1 | :: 2 | :::: /hoon/json/mar 3 | :: 4 | /? 310 5 | :: 6 | :::: compute 7 | :: 8 | =, eyre 9 | =, format 10 | =, html 11 | |_ jon=^json 12 | :: 13 | ++ grow :: convert to 14 | |% 15 | ++ mime [/application/json (as-octs:mimes -:txt)] :: convert to %mime 16 | ++ txt [(en:json jon)]~ 17 | -- 18 | ++ grab 19 | |% :: convert from 20 | ++ mime |=([p=mite q=octs] (fall (de:json (@t q.q)) *^json)) 21 | ++ noun ^json :: clam from %noun 22 | ++ numb numb:enjs 23 | ++ time time:enjs 24 | -- 25 | ++ grad %mime 26 | -- 27 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/kelvin.hoon: -------------------------------------------------------------------------------- 1 | |_ kal=waft:clay 2 | ++ grow 3 | |% 4 | ++ mime `^mime`[/text/x-kelvin (as-octs:mimes:html hoon)] 5 | ++ noun kal 6 | ++ hoon 7 | %+ rap 3 8 | %+ turn 9 | %+ sort 10 | ~(tap in (waft-to-wefts:clay kal)) 11 | |= [a=weft b=weft] 12 | ?: =(lal.a lal.b) 13 | (gte num.a num.b) 14 | (gte lal.a lal.b) 15 | |= =weft 16 | (rap 3 '[%' (scot %tas lal.weft) ' ' (scot %ud num.weft) ']\0a' ~) 17 | :: 18 | ++ txt (to-wain:format hoon) 19 | -- 20 | ++ grab 21 | |% 22 | ++ noun waft:clay 23 | ++ mime 24 | |= [=mite len=@ud tex=@] 25 | (cord-to-waft:clay tex) 26 | -- 27 | ++ grad %noun 28 | -- 29 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/mime.hoon: -------------------------------------------------------------------------------- 1 | :: 2 | :::: /hoon/mime/mar 3 | :: 4 | /? 310 5 | :: 6 | |_ own=mime 7 | ++ grow 8 | ^? 9 | |% 10 | ++ jam `@`q.q.own 11 | -- 12 | :: 13 | ++ grab :: convert from 14 | ^? 15 | |% 16 | ++ noun mime :: clam from %noun 17 | ++ tape 18 | |=(a=_"" [/application/x-urb-unknown (as-octt:mimes:html a)]) 19 | -- 20 | ++ grad 21 | ^? 22 | |% 23 | ++ form %mime 24 | ++ diff |=(mime +<) 25 | ++ pact |=(mime +<) 26 | ++ join |=([mime mime] `(unit mime)`~) 27 | ++ mash 28 | |= [[ship desk mime] [ship desk mime]] 29 | ^- mime 30 | ~|(%mime-mash !!) 31 | -- 32 | -- 33 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/noun.hoon: -------------------------------------------------------------------------------- 1 | :: 2 | :::: /hoon/noun/mar 3 | :: 4 | /? 310 5 | !: 6 | :::: A minimal noun mark 7 | |_ non=* 8 | ++ grab |% 9 | ++ noun * 10 | -- 11 | ++ grow |% 12 | ++ mime [/application/x-urb-jam (as-octs:mimes:html (jam non))] 13 | -- 14 | ++ grad 15 | |% 16 | ++ form %noun 17 | ++ diff |=(* +<) 18 | ++ pact |=(* +<) 19 | ++ join |=([* *] *(unit *)) 20 | ++ mash |=([[ship desk *] [ship desk *]] `*`~|(%noun-mash !!)) 21 | -- 22 | -- 23 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/ship.hoon: -------------------------------------------------------------------------------- 1 | |_ s=ship 2 | ++ grad %noun 3 | ++ grow 4 | |% 5 | ++ noun s 6 | ++ json s+(scot %p s) 7 | ++ mime 8 | ^- ^mime 9 | [/text/x-ship (as-octt:mimes:html (scow %p s))] 10 | 11 | -- 12 | ++ grab 13 | |% 14 | ++ noun ship 15 | ++ json (su:dejs:format ;~(pfix sig fed:ag)) 16 | ++ mime 17 | |= [=mite len=@ tex=@] 18 | (slav %p (snag 0 (to-wain:format tex))) 19 | -- 20 | -- 21 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/txt-diff.hoon: -------------------------------------------------------------------------------- 1 | :: 2 | :::: /hoon/txt-diff/mar 3 | :: 4 | /? 310 5 | |_ txt-diff=(urge:clay cord) 6 | :: 7 | ++ grad %noun 8 | ++ grow 9 | |% 10 | ++ noun txt-diff 11 | -- 12 | ++ grab :: convert from 13 | |% 14 | ++ noun (urge:clay cord) :: make from %noun 15 | -- 16 | -- 17 | -------------------------------------------------------------------------------- /chat-app/full-desk/mar/txt.hoon: -------------------------------------------------------------------------------- 1 | :: 2 | :::: /hoon/txt/mar 3 | :: 4 | /? 310 5 | :: 6 | =, clay 7 | =, differ 8 | =, format 9 | =, mimes:html 10 | |_ txt=wain 11 | :: 12 | ++ grab :: convert from 13 | |% 14 | ++ mime |=((pair mite octs) (to-wain q.q)) 15 | ++ noun wain :: clam from %noun 16 | -- 17 | ++ grow 18 | => v=. 19 | |% 20 | ++ mime => v [/text/plain (as-octs (of-wain txt))] 21 | -- 22 | ++ grad 23 | |% 24 | ++ form %txt-diff 25 | ++ diff 26 | |= tyt=wain 27 | ^- (urge cord) 28 | (lusk txt tyt (loss txt tyt)) 29 | :: 30 | ++ pact 31 | |= dif=(urge cord) 32 | ~| [%pacting dif] 33 | ^- wain 34 | (lurk txt dif) 35 | :: 36 | ++ join 37 | |= [ali=(urge cord) bob=(urge cord)] 38 | ^- (unit (urge cord)) 39 | |^ 40 | =. ali (clean ali) 41 | =. bob (clean bob) 42 | |- ^- (unit (urge cord)) 43 | ?~ ali `bob 44 | ?~ bob `ali 45 | ?- -.i.ali 46 | %& 47 | ?- -.i.bob 48 | %& 49 | ?: =(p.i.ali p.i.bob) 50 | %+ bind $(ali t.ali, bob t.bob) 51 | |=(cud=(urge cord) [i.ali cud]) 52 | ?: (gth p.i.ali p.i.bob) 53 | %+ bind $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob) 54 | |=(cud=(urge cord) [i.bob cud]) 55 | %+ bind $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali)) 56 | |=(cud=(urge cord) [i.ali cud]) 57 | :: 58 | %| 59 | ?: =(p.i.ali (lent p.i.bob)) 60 | %+ bind $(ali t.ali, bob t.bob) 61 | |=(cud=(urge cord) [i.bob cud]) 62 | ?: (gth p.i.ali (lent p.i.bob)) 63 | %+ bind $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob) 64 | |=(cud=(urge cord) [i.bob cud]) 65 | ~ 66 | == 67 | :: 68 | %| 69 | ?- -.i.bob 70 | %| 71 | ?. =(i.ali i.bob) 72 | ~ 73 | %+ bind $(ali t.ali, bob t.bob) 74 | |=(cud=(urge cord) [i.ali cud]) 75 | :: 76 | %& 77 | ?: =(p.i.bob (lent p.i.ali)) 78 | %+ bind $(ali t.ali, bob t.bob) 79 | |=(cud=(urge cord) [i.ali cud]) 80 | ?: (gth p.i.bob (lent p.i.ali)) 81 | %+ bind $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali))) 82 | |=(cud=(urge cord) [i.ali cud]) 83 | ~ 84 | == 85 | == 86 | ++ clean :: clean 87 | |= wig=(urge cord) 88 | ^- (urge cord) 89 | ?~ wig ~ 90 | ?~ t.wig wig 91 | ?: ?=(%& -.i.wig) 92 | ?: ?=(%& -.i.t.wig) 93 | $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig]) 94 | [i.wig $(wig t.wig)] 95 | ?: ?=(%| -.i.t.wig) 96 | $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig]) 97 | [i.wig $(wig t.wig)] 98 | -- 99 | :: 100 | ++ mash 101 | |= $: [als=ship ald=desk ali=(urge cord)] 102 | [bos=ship bod=desk bob=(urge cord)] 103 | == 104 | ^- (urge cord) 105 | |^ 106 | =. ali (clean ali) 107 | =. bob (clean bob) 108 | |- ^- (urge cord) 109 | ?~ ali bob 110 | ?~ bob ali 111 | ?- -.i.ali 112 | %& 113 | ?- -.i.bob 114 | %& 115 | ?: =(p.i.ali p.i.bob) 116 | [i.ali $(ali t.ali, bob t.bob)] 117 | ?: (gth p.i.ali p.i.bob) 118 | [i.bob $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob)] 119 | [i.ali $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali))] 120 | :: 121 | %| 122 | ?: =(p.i.ali (lent p.i.bob)) 123 | [i.bob $(ali t.ali, bob t.bob)] 124 | ?: (gth p.i.ali (lent p.i.bob)) 125 | [i.bob $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob)] 126 | =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)] 127 | (resolve ali bob) 128 | [fic $(ali ali, bob bob)] 129 | :: ~ :: here, alice is good for a while, but not for the whole 130 | == :: length of bob's changes 131 | :: 132 | %| 133 | ?- -.i.bob 134 | %| 135 | =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)] 136 | (resolve ali bob) 137 | [fic $(ali ali, bob bob)] 138 | :: 139 | %& 140 | ?: =(p.i.bob (lent p.i.ali)) 141 | [i.ali $(ali t.ali, bob t.bob)] 142 | ?: (gth p.i.bob (lent p.i.ali)) 143 | [i.ali $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali)))] 144 | =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)] 145 | (resolve ali bob) 146 | [fic $(ali ali, bob bob)] 147 | == 148 | == 149 | :: 150 | ++ annotate :: annotate conflict 151 | |= $: ali=(list @t) 152 | bob=(list @t) 153 | bas=(list @t) 154 | == 155 | ^- (list @t) 156 | %- zing 157 | ^- (list (list @t)) 158 | %- flop 159 | ^- (list (list @t)) 160 | :- :_ ~ 161 | %^ cat 3 '<<<<<<<<<<<<' 162 | %^ cat 3 ' ' 163 | %^ cat 3 `@t`(scot %p bos) 164 | %^ cat 3 '/' 165 | bod 166 | 167 | :- bob 168 | :- ~['------------'] 169 | :- bas 170 | :- ~['++++++++++++'] 171 | :- ali 172 | :- :_ ~ 173 | %^ cat 3 '>>>>>>>>>>>>' 174 | %^ cat 3 ' ' 175 | %^ cat 3 `@t`(scot %p als) 176 | %^ cat 3 '/' 177 | ald 178 | ~ 179 | :: 180 | ++ clean :: clean 181 | |= wig=(urge cord) 182 | ^- (urge cord) 183 | ?~ wig ~ 184 | ?~ t.wig wig 185 | ?: ?=(%& -.i.wig) 186 | ?: ?=(%& -.i.t.wig) 187 | $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig]) 188 | [i.wig $(wig t.wig)] 189 | ?: ?=(%| -.i.t.wig) 190 | $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig]) 191 | [i.wig $(wig t.wig)] 192 | :: 193 | ++ resolve 194 | |= [ali=(urge cord) bob=(urge cord)] 195 | ^- [fic=[%| p=(list cord) q=(list cord)] ali=(urge cord) bob=(urge cord)] 196 | =- [[%| bac (annotate alc boc bac)] ali bob] 197 | |- ^- $: $: bac=(list cord) 198 | alc=(list cord) 199 | boc=(list cord) 200 | == 201 | ali=(urge cord) 202 | bob=(urge cord) 203 | == 204 | ?~ ali [[~ ~ ~] ali bob] 205 | ?~ bob [[~ ~ ~] ali bob] 206 | ?- -.i.ali 207 | %& 208 | ?- -.i.bob 209 | %& [[~ ~ ~] ali bob] :: no conflict 210 | %| 211 | =+ lob=(lent p.i.bob) 212 | ?: =(lob p.i.ali) 213 | [[p.i.bob p.i.bob q.i.bob] t.ali t.bob] 214 | ?: (lth lob p.i.ali) 215 | [[p.i.bob p.i.bob q.i.bob] [[%& (sub p.i.ali lob)] t.ali] t.bob] 216 | =+ wat=(scag (sub lob p.i.ali) p.i.bob) 217 | =+ ^= res 218 | %= $ 219 | ali t.ali 220 | bob [[%| (scag (sub lob p.i.ali) p.i.bob) ~] t.bob] 221 | == 222 | :* :* (welp bac.res wat) 223 | (welp alc.res wat) 224 | (welp boc.res q.i.bob) 225 | == 226 | ali.res 227 | bob.res 228 | == 229 | == 230 | :: 231 | %| 232 | ?- -.i.bob 233 | %& 234 | =+ loa=(lent p.i.ali) 235 | ?: =(loa p.i.bob) 236 | [[p.i.ali q.i.ali p.i.ali] t.ali t.bob] 237 | ?: (lth loa p.i.bob) 238 | [[p.i.ali q.i.ali p.i.ali] t.ali [[%& (sub p.i.bob loa)] t.bob]] 239 | =+ wat=(slag (sub loa p.i.bob) p.i.ali) 240 | =+ ^= res 241 | %= $ 242 | ali [[%| (scag (sub loa p.i.bob) p.i.ali) ~] t.ali] 243 | bob t.bob 244 | == 245 | :* :* (welp bac.res wat) 246 | (welp alc.res q.i.ali) 247 | (welp boc.res wat) 248 | == 249 | ali.res 250 | bob.res 251 | == 252 | :: 253 | %| 254 | =+ loa=(lent p.i.ali) 255 | =+ lob=(lent p.i.bob) 256 | ?: =(loa lob) 257 | [[p.i.ali q.i.ali q.i.bob] t.ali t.bob] 258 | =+ ^= res 259 | ?: (gth loa lob) 260 | $(ali [[%| (scag (sub loa lob) p.i.ali) ~] t.ali], bob t.bob) 261 | ~& [%scagging loa=loa pibob=p.i.bob slag=(scag loa p.i.bob)] 262 | $(ali t.ali, bob [[%| (scag (sub lob loa) p.i.bob) ~] t.bob]) 263 | :* :* (welp bac.res ?:((gth loa lob) p.i.bob p.i.ali)) 264 | (welp alc.res q.i.ali) 265 | (welp boc.res q.i.bob) 266 | == 267 | ali.res 268 | bob.res 269 | == 270 | == 271 | == 272 | -- 273 | -- 274 | -- 275 | -------------------------------------------------------------------------------- /chat-app/full-desk/sur/docket.hoon: -------------------------------------------------------------------------------- 1 | |% 2 | :: 3 | +$ version 4 | [major=@ud minor=@ud patch=@ud] 5 | :: 6 | +$ glob (map path mime) 7 | :: 8 | +$ url cord 9 | :: $glob-location: How to retrieve a glob 10 | :: 11 | +$ glob-reference 12 | [hash=@uvH location=glob-location] 13 | :: 14 | +$ glob-location 15 | $% [%http =url] 16 | [%ames =ship] 17 | == 18 | :: $href: Where a tile links to 19 | :: 20 | +$ href 21 | $% [%glob base=term =glob-reference] 22 | [%site =path] 23 | == 24 | :: $chad: State of a docket 25 | :: 26 | +$ chad 27 | $~ [%install ~] 28 | $% :: Done 29 | [%glob =glob] 30 | [%site ~] 31 | :: Waiting 32 | [%install ~] 33 | [%suspend glob=(unit glob)] 34 | :: Error 35 | [%hung err=cord] 36 | == 37 | :: 38 | :: $charge: A realized $docket 39 | :: 40 | +$ charge 41 | $: =docket 42 | =chad 43 | == 44 | :: 45 | :: $clause: A key and value, as part of a docket 46 | :: 47 | :: Only used to parse $docket 48 | :: 49 | +$ clause 50 | $% [%title title=@t] 51 | [%info info=@t] 52 | [%color color=@ux] 53 | [%glob-http url=cord hash=@uvH] 54 | [%glob-ames =ship hash=@uvH] 55 | [%image =url] 56 | [%site =path] 57 | [%base base=term] 58 | [%version =version] 59 | [%website website=url] 60 | [%license license=cord] 61 | == 62 | :: 63 | :: $docket: A description of JS bundles for a desk 64 | :: 65 | +$ docket 66 | $: %1 67 | title=@t 68 | info=@t 69 | color=@ux 70 | =href 71 | image=(unit url) 72 | =version 73 | website=url 74 | license=cord 75 | == 76 | :: 77 | +$ charge-update 78 | $% [%initial initial=(map desk charge)] 79 | [%add-charge =desk =charge] 80 | [%del-charge =desk] 81 | == 82 | -- 83 | -------------------------------------------------------------------------------- /chat-app/full-desk/sur/hut.hoon: -------------------------------------------------------------------------------- 1 | ../../bare-desk/sur/hut.hoon -------------------------------------------------------------------------------- /chat-app/full-desk/sur/squad.hoon: -------------------------------------------------------------------------------- 1 | |% 2 | +$ gid [host=@p name=@tas] 3 | +$ title @t 4 | +$ ppl (set @p) 5 | +$ squad [=title pub=?] 6 | :: 7 | +$ squads (map gid squad) 8 | +$ acls (jug gid @p) 9 | +$ members (jug gid @p) 10 | :: 11 | +$ act 12 | $% [%new =title pub=?] 13 | [%del =gid] 14 | [%allow =gid =ship] 15 | [%kick =gid =ship] 16 | [%join =gid] 17 | [%leave =gid] 18 | [%pub =gid] 19 | [%priv =gid] 20 | [%title =gid =title] 21 | == 22 | +$ upd 23 | $% [%init-all =squads =acls =members] 24 | [%init =gid =squad acl=ppl =ppl] 25 | [%del =gid] 26 | [%allow =gid =ship] 27 | [%kick =gid =ship] 28 | [%join =gid =ship] 29 | [%leave =gid =ship] 30 | [%pub =gid] 31 | [%priv =gid] 32 | [%title =gid =title] 33 | == 34 | :: 35 | +$ page [sect=@t gid=(unit gid) success=?] 36 | -- 37 | -------------------------------------------------------------------------------- /chat-app/full-desk/sys.kelvin: -------------------------------------------------------------------------------- 1 | ../bare-desk/sys.kelvin -------------------------------------------------------------------------------- /chat-app/ui/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | stats.html 7 | .eslintcache 8 | .vercel -------------------------------------------------------------------------------- /chat-app/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | hut 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /chat-app/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hut", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "serve": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@urbit/api": "^2.0.0", 12 | "@urbit/http-api": "^2.0.0", 13 | "@urbit/foundation-design-system": "^0.7.5", 14 | "react": "^17.0.2", 15 | "react-dom": "^17.0.2" 16 | }, 17 | "devDependencies": { 18 | "@urbit/vite-plugin-urbit": "^0.8.0", 19 | "@vitejs/plugin-react-refresh": "^1.3.1", 20 | "autoprefixer": "^10.4.12", 21 | "postcss": "^8.4.18", 22 | "tailwindcss": "^3.2.1", 23 | "vite": "^2.6.7" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chat-app/ui/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | } 6 | } -------------------------------------------------------------------------------- /chat-app/ui/src/api.js: -------------------------------------------------------------------------------- 1 | import Urbit from "@urbit/http-api"; 2 | 3 | const api = new Urbit("", "", window.desk); 4 | api.ship = window.ship; 5 | 6 | export default api; 7 | -------------------------------------------------------------------------------- /chat-app/ui/src/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | @apply bg-white text-wall-600 h-screen w-screen; 3 | margin: 0; 4 | } 5 | * { 6 | @apply font-sans; 7 | font-size: 1rem; 8 | box-sizing: border-box; 9 | } 10 | div#app { 11 | height: 100%; 12 | width: 100%; 13 | max-width: 100%; 14 | padding: 2ch; 15 | display: flex; 16 | flex-direction: column; 17 | justify-content: stretch; 18 | } 19 | .top-bar { 20 | flex: 0 0 auto; 21 | display: flex; 22 | flex-direction: row; 23 | justify-content: space-between; 24 | margin: 1em 0; 25 | } 26 | .gid-title { 27 | @apply text-ellipsis whitespace-nowrap block overflow-hidden font-semibold; 28 | margin: 0 1ch; 29 | } 30 | .join-span { 31 | display: block; 32 | white-space: nowrap; 33 | } 34 | .join-select { 35 | width: 9ch; 36 | text-overflow: ellipsis; 37 | } 38 | .join-button { 39 | @apply bg-green-400 text-white rounded-md px-2 font-medium ml-2 inline-block text-center; 40 | border: none; 41 | cursor: pointer; 42 | } 43 | main { 44 | @apply flex flex-1 w-full; 45 | justify-content: stretch; 46 | height: calc(100% - 16em); 47 | } 48 | .left-menu { 49 | @apply overflow-hidden flex flex-col h-full border rounded-lg mr-4 p-2 border-wall-200; 50 | flex: 0 0 auto; 51 | justify-content: stretch; 52 | } 53 | .hut-list { 54 | margin-top: auto; 55 | width: 100%; 56 | overflow: hidden; 57 | display: flex; 58 | flex-direction: column; 59 | overflow-y: auto; 60 | flex: 1 1 auto; 61 | } 62 | .make-hut { 63 | @apply mb-4 rounded-md p-1; 64 | width: 13ch; 65 | flex: 0 0 auto; 66 | display: block; 67 | } 68 | .content { 69 | @apply border flex flex-col flex-1 border-wall-200 rounded-lg; 70 | justify-content: stretch; 71 | overflow: hidden; 72 | } 73 | .msgs { 74 | height: 100%; 75 | overflow-y: auto; 76 | display: flex; 77 | flex-direction: column; 78 | flex: 1 1 auto; 79 | } 80 | .msg { 81 | margin: 0.4em 0.4em 0 16ch; 82 | text-indent: -16ch; 83 | } 84 | .who { 85 | @apply font-medium; 86 | width: 16ch; 87 | text-align: right; 88 | padding-right: 1ch; 89 | display: inline-block; 90 | } 91 | .what { 92 | overflow-wrap: break-word; 93 | text-overflow: ellipsis; 94 | } 95 | .right-menu { 96 | height: 100%; 97 | width: 16ch; 98 | flex: 0 0 auto; 99 | padding-left: 2ch; 100 | display: flex; 101 | flex-direction: column; 102 | justify-content: stretch; 103 | } 104 | .leave-button { 105 | flex: 0 0 auto; 106 | width: 100%; 107 | margin-bottom: 1em; 108 | @apply bg-red rounded-md text-white font-medium cursor-pointer border-0 p-0; 109 | width: 14ch; 110 | } 111 | .ppl { 112 | @apply flex-1 border rounded-lg p-2 border-wall-200; 113 | overflow-y: auto; 114 | } 115 | input, textarea { 116 | @apply bg-white border border-wall-200; 117 | } 118 | .our { 119 | width: 14ch; 120 | display: inline-block; 121 | text-align: right; 122 | flex: 0 0 auto; 123 | align-self: center; 124 | margin-right: 2ch; 125 | } 126 | .input { 127 | flex: 0 0 auto; 128 | display: flex; 129 | flex-direction: row; 130 | justify-content: stretch; 131 | height: 6em; 132 | margin: 1em 0; 133 | } 134 | textarea { 135 | flex: 1 1 auto; 136 | border-radius: 10px; 137 | margin-right: 1em; 138 | resize: none; 139 | } 140 | select { 141 | @apply bg-white; 142 | border: 0; 143 | cursor: pointer; 144 | } 145 | .fix {flex: 1 1 auto} 146 | label { 147 | display: inline-block; 148 | width: 8ch; 149 | } 150 | .conn { 151 | flex: 0 0 auto; 152 | font-size: 0.9em; 153 | text-align: right; 154 | } 155 | .out {color: rgba(216, 216, 216, 0.5)} 156 | .current-hut { 157 | @apply text-green-400 border-wall-400 border; 158 | border-radius: 6px; 159 | } 160 | .other-hut { 161 | @apply text-wall-500; 162 | } 163 | .other-hut:hover { 164 | opacity: 0.8; 165 | } 166 | .current-hut, .other-hut { 167 | overflow: hidden; 168 | text-overflow: ellipsis; 169 | padding: 10px 0.5ch; 170 | margin-right: 1ch; 171 | flex: 0 0 auto; 172 | cursor: pointer; 173 | } 174 | .current-hut:first-child, .other-hut:first-child { 175 | margin-top: auto; 176 | } 177 | .current-hut:last-child, .other-hut:last-child { 178 | margin-bottom: auto; 179 | } 180 | .selectgid { 181 | margin-top: 0.5em; 182 | margin-bottom: 0.5em; 183 | display: flex; 184 | flex-direction: row; 185 | justify-content: space-between; 186 | } 187 | .gid-select { 188 | width: 13ch; 189 | } 190 | @media only screen and (max-width: 800px) { 191 | .right-menu {display: none} 192 | .our {display: none} 193 | textarea {margin-left: 1em} 194 | .msg {margin-left: 1ch; text-indent: initial} 195 | .who {width: initial} 196 | select {max-width: 14ch} 197 | } 198 | -------------------------------------------------------------------------------- /chat-app/ui/src/app.jsx: -------------------------------------------------------------------------------- 1 | import React, {useState, useEffect} from "react"; 2 | import ConnStatus from "./components/ConnStatus"; 3 | import SelectGid from "./components/SelectGid"; 4 | import Huts from "./components/Huts"; 5 | import ChatInput from "./components/ChatInput"; 6 | import People from "./components/People"; 7 | import Messages from "./components/Messages"; 8 | import { appPoke, gidToStr, hutToStr } from "~/lib"; 9 | import { OUR } from "~/const"; 10 | import api from "~/api"; 11 | import "~/app.css"; 12 | 13 | export default function App() { 14 | const [subEvent, setSubEvent] = useState({}); // object 15 | const [conn, setConn] = useState(null); // string? 16 | 17 | // gid: ~host/squad-name 18 | // hut: hut-name 19 | const [squads, setSquads] = useState(new Map()); // gid => title 20 | const [huts, setHuts] = useState(new Map()); // gid => {hut, ...} 21 | const [chatContents, setChatContents] = useState(new Map()); // hut => [string, ...] 22 | const [chatMembers, setChatMembers] = useState(new Map()); // gid => {~member, ...} 23 | 24 | const [chatInput, setChatInput] = useState(""); // string 25 | const [hutInput, setHutInput] = useState(""); // string 26 | const [joinSelect, setJoinSelect] = useState("def"); // string (option) 27 | const [viewSelect, setViewSelect] = useState("def"); // string (option) 28 | const [currGid, setCurrGid] = useState(null); // gid? 29 | const [currHut, setCurrHut] = useState(null); // hut? 30 | 31 | useEffect(() => { 32 | api.onOpen = () => setConn("ok"); 33 | api.onRetry = () => setConn("try"); 34 | api.onError = () => setConn("err"); 35 | 36 | const subscription = api.subscribe({ 37 | app: "hut", 38 | path: "/all", 39 | event: setSubEvent, 40 | }); 41 | return () => { 42 | api.unsubscribe(subscription); 43 | }; 44 | }, [api]); 45 | 46 | useEffect(() => { 47 | api.scry({ 48 | app: "squad", 49 | path: "/titles", 50 | }).then((titles) => { 51 | let newHuts = new Map(); 52 | titles.forEach(obj => { 53 | const gidStr = gidToStr(obj.gid); 54 | if (!newHuts.has(gidStr) && (obj.gid.host === OUR)) { 55 | newHuts.set(gidStr, new Set()); 56 | } 57 | }); 58 | const newSquads = new Map( 59 | titles.map(obj => [gidToStr(obj.gid), obj.title]) 60 | ); 61 | 62 | setHuts(newHuts); 63 | setSquads(newSquads); 64 | }); 65 | }, []); 66 | 67 | useEffect(() => { 68 | const updateFuns = { 69 | "initAll": (update) => { 70 | update.huts.forEach(obj => 71 | huts.set(gidToStr(obj.gid), new Set(obj.names)) 72 | ); 73 | 74 | setHuts(new Map(huts)); 75 | setChatContents(new Map( 76 | update.msgJar.map(o => [hutToStr(o.hut), o.msgs]) 77 | )); 78 | setChatMembers(new Map( 79 | update.joined.map(o => [gidToStr(o.gid), new Set(o.ppl)]) 80 | )); 81 | }, "init": (update) => { 82 | setChatContents(new Map(update.msgJar.reduce( 83 | (a, n) => a.set(hutToStr(n.hut), n.msgs) 84 | , chatContents))); 85 | setHuts(new Map(huts.set( 86 | gidToStr(update.huts[0].gid), 87 | new Set(update.huts[0].names) 88 | ))); 89 | setChatMembers(new Map(chatMembers.set( 90 | gidToStr(update.joined[0].gid), 91 | new Set(update.joined[0].ppl) 92 | ))); 93 | }, "new": (update) => { 94 | const gidStr = gidToStr(update.hut.gid); 95 | const hutStr = hutToStr(update.hut); 96 | if (huts.has(gidStr)) { 97 | huts.get(gidStr).add(update.hut.name); 98 | } else { 99 | huts.set(gidStr, new Set(update.hut.name)); 100 | } 101 | 102 | setHuts(new Map(huts)); 103 | setChatMembers(new Map(chatMembers.set(hutStr, update.msgs))); 104 | }, "post": (update) => { 105 | const newHut = hutToStr(update.hut); 106 | if (chatContents.has(newHut)) { 107 | chatContents.set(newHut, [...chatContents.get(newHut), update.msg]); 108 | } else { 109 | chatContents.set(newHut, [update.msg]); 110 | } 111 | 112 | setChatContents(new Map(chatContents)); 113 | }, "join": (update) => { 114 | const gidStr = gidToStr(update.gid); 115 | if (chatMembers.has(gidStr)) { 116 | chatMembers.get(gidStr).add(update.who) 117 | } else { 118 | chatMembers.set(gidStr, new Set([update.who])); 119 | } 120 | 121 | setChatMembers(new Map(chatMembers)); 122 | setJoinSelect("def"); 123 | }, "quit": (update) => { 124 | const gidStr = gidToStr(update.gid); 125 | if (update.who === OUR) { 126 | huts.delete(gidStr); 127 | chatMembers.delete(gidStr); 128 | if(huts.has(gidStr)) { 129 | huts.get(gidStr).forEach(name => 130 | chatContents.delete(gidStr + "/" + name) 131 | ); 132 | } 133 | 134 | setHuts(new Map(huts)); 135 | setChatMembers(new Map(chatMembers)); 136 | setChatContents(new Map(chatContents)); 137 | setCurrGid((currGid === gidStr) ? null : currGid); 138 | setCurrHut((currHut === null) 139 | ? null 140 | : (`${currHut.split("/")[0]}/${currHut.split("/")[1]}` === gidStr) 141 | ? null 142 | : currHut 143 | ); 144 | setViewSelect("def"); 145 | setHutInput((currGid === gidStr) ? "" : hutInput); 146 | } else { 147 | if (chatMembers.has(gidStr)) { 148 | chatMembers.get(gidStr).delete(update.who); 149 | } 150 | 151 | setChatMembers(new Map(chatMembers)); 152 | } 153 | }, "del": (update) => { 154 | const gidStr = gidToStr(update.hut.gid); 155 | const hutStr = hutToStr(update.hut); 156 | if (huts.has(gidStr)) { 157 | huts.get(gidStr).delete(update.hut.name); 158 | } 159 | chatContents.delete(hutStr); 160 | 161 | setHuts(new Map(huts)); 162 | setChatContents(new Map(chatContents)); 163 | setCurrHut((currHut === hutStr) ? null : currHut); 164 | }, 165 | }; 166 | 167 | const eventTypes = Object.keys(subEvent); 168 | if (eventTypes.length > 0) { 169 | const eventType = eventTypes[0]; 170 | updateFuns[eventType](subEvent[eventType]); 171 | } 172 | }, [subEvent]); 173 | 174 | return ( 175 | 176 | 177 | {setCurrGid(e); setCurrHut(null); setHutInput("");}} 182 | viewSelect={viewSelect} 183 | setView={setViewSelect} 184 | joinSelect={joinSelect} 185 | setJoin={setJoinSelect} 186 | /> 187 |
188 | `${currGid}/${name}`) 192 | } 193 | input={hutInput} 194 | setInput={setHutInput} 195 | currHut={currHut} 196 | setHut={setCurrHut} 197 | currGid={currGid} 198 | /> 199 |
200 | 206 | 210 |
211 | 221 |
222 |
223 | ); 224 | } 225 | -------------------------------------------------------------------------------- /chat-app/ui/src/assets/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urbit/docs-examples/13446c48d0eb1de53bd6e5eca881e748b9fe0f98/chat-app/ui/src/assets/android-chrome-512x512.png -------------------------------------------------------------------------------- /chat-app/ui/src/assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urbit/docs-examples/13446c48d0eb1de53bd6e5eca881e748b9fe0f98/chat-app/ui/src/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /chat-app/ui/src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urbit/docs-examples/13446c48d0eb1de53bd6e5eca881e748b9fe0f98/chat-app/ui/src/assets/favicon.ico -------------------------------------------------------------------------------- /chat-app/ui/src/assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /chat-app/ui/src/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hut", 3 | "short_name": "hut", 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 | } 15 | -------------------------------------------------------------------------------- /chat-app/ui/src/assets/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 23 | 34 | 42 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /chat-app/ui/src/components/ChatInput.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { appPoke, patpShorten } from "~/lib"; 3 | import { OUR } from "~/const"; 4 | 5 | export default function ChatInput({ 6 | input, 7 | setInput, 8 | currHut, 9 | }) { 10 | const handleKey = (e) => { 11 | const trimmed = input.trim(); 12 | if ((e.key === "Enter") && !e.shiftKey 13 | && (trimmed !== "") 14 | && (currHut !== null)) { 15 | const [host, gidName, hutName] = currHut.split("/"); 16 | appPoke({ 17 | "post": { 18 | "hut": {"gid": {"host": host, "name": gidName}, "name": hutName}, 19 | "msg": {"who": OUR, "what": trimmed} 20 | } 21 | }); 22 | setInput(""); 23 | } 24 | }; 25 | 26 | return (currHut !== null) && ( 27 |
28 | {patpShorten(OUR)} 29 |