mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-13 08:38:43 +03:00
Merge branch 'release/next-userspace' into lf/global-skeleton-links
This commit is contained in:
commit
bda2770320
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,8 +1,11 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Landscape design issue
|
||||
url: https://github.com/urbit/landscape/issues/new?assignees=&labels=design+issue&template=report-a-design-issue.md&title=
|
||||
about: Submit non-functionality, design-specific issues to the Landscape team here.
|
||||
- name: Landscape feature request
|
||||
url: https://github.com/urbit/landscape/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=
|
||||
about: Landscape is comprised of Tlon's user applications and client for Urbit. Submit Landscape feature requests here.
|
||||
- name: urbit-dev mailing list
|
||||
url: https://groups.google.com/a/urbit.org/g/dev
|
||||
about: Developer questions and discussions also take place on the urbit-dev mailing list.
|
||||
about: Developer questions and discussions also take place on the urbit-dev mailing list.
|
||||
|
@ -38,6 +38,17 @@ To resume a fake ship, just pass the name of the pier:
|
||||
$ urbit my-fake-zod
|
||||
```
|
||||
|
||||
Fake ships by default use the same pre-compiled kernelspace ('pills') as livenet
|
||||
ships do: boot pills, which are not always current with `master`. If you wish to
|
||||
develop using code off the master branch, run the following from the repo
|
||||
directory:
|
||||
|
||||
```
|
||||
git lfs install
|
||||
git lfs pull
|
||||
urbit -F zod -B "bin/solid.pill" -A "pkg/arvo"
|
||||
```
|
||||
|
||||
## Git practice
|
||||
|
||||
### Contributing
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:eab360913b845f8775002cfe1830defcd252b490ac90e8dfa093297b56531392
|
||||
size 19090656
|
||||
oid sha256:b1ae413b0ac4cc6ddd4f4e7e380852171a4b28436e1c4bff693425c3acbca473
|
||||
size 6229799
|
||||
|
@ -33,7 +33,7 @@ To boot a fake ship with a custom pill, use the `-B` flag:
|
||||
urbit -F zod -A /path/to/arvo -B /path/to.pill -c fakezod
|
||||
```
|
||||
|
||||
To run all tests in `/tests`, run `+test` in dojo. `+test /some/path` would only run all tests in `/tests/some/path`.
|
||||
To run all tests in `/tests`, run `-test %/tests` in dojo. To run only the tests in `/tests/some/path`, use `-test %/tests/some/path`.
|
||||
|
||||
## Maintainers
|
||||
|
||||
|
@ -23,8 +23,12 @@
|
||||
state-6
|
||||
state-7
|
||||
state-8
|
||||
state-9
|
||||
state-10
|
||||
==
|
||||
::
|
||||
+$ state-10 [%10 state-base]
|
||||
+$ state-9 [%9 state-base]
|
||||
+$ state-8 [%8 state-base]
|
||||
+$ state-7 [%7 state-base]
|
||||
+$ state-6 [%6 state-base]
|
||||
@ -56,7 +60,7 @@
|
||||
$% [%chat-update update:store]
|
||||
==
|
||||
--
|
||||
=| state-8
|
||||
=| state-10
|
||||
=* state -
|
||||
::
|
||||
%- agent:dbug
|
||||
@ -85,8 +89,47 @@
|
||||
=/ old !<(versioned-state old-vase)
|
||||
=| cards=(list card)
|
||||
|-
|
||||
?: ?=(%8 -.old)
|
||||
?: ?=(%10 -.old)
|
||||
[cards this(state old)]
|
||||
?: ?=(%9 -.old)
|
||||
=. cards
|
||||
%+ weld cards
|
||||
^- (list card)
|
||||
%+ roll ~(tap in ~(key by wex.bol))
|
||||
|= [[=wire =ship =term] out=(list card)]
|
||||
?> ?=([@ *] wire)
|
||||
?. ?&(=(ship our.bol) =(term %chat-hook))
|
||||
out
|
||||
:_ out
|
||||
=- [%pass / %agent [our.bol %chat-hook] %poke %chat-hook-action !>(-)]
|
||||
[%remove t.wire]
|
||||
=/ chat-keys=(set path) (scry-for (set path) %chat-store [%keys ~])
|
||||
=. cards
|
||||
%+ weld cards
|
||||
^- (list card)
|
||||
%+ turn ~(tap in chat-keys)
|
||||
|= =app=path
|
||||
^- card
|
||||
?> ?=([@ @ ~] app-path)
|
||||
=/ =ship (slav %p i.app-path)
|
||||
?: =(ship our.bol)
|
||||
(add-owned app-path %.y)
|
||||
(add-synced ship app-path)
|
||||
::
|
||||
=/ list-paths=(list path)
|
||||
%+ murn ~(tap in ~(key by synced.old))
|
||||
|= =app=path
|
||||
^- (unit path)
|
||||
?~ (groups-of-chat:cc app-path)
|
||||
`app-path
|
||||
~
|
||||
|-
|
||||
?~ list-paths
|
||||
^$(-.old %10)
|
||||
=. synced.old (~(del by synced.old) i.list-paths)
|
||||
$(list-paths t.list-paths)
|
||||
?: ?=(%8 -.old)
|
||||
$(-.old %9)
|
||||
?: ?=(%7 -.old)
|
||||
=/ subscribers=(jug path ship)
|
||||
%+ roll ~(val by sup.bol)
|
||||
@ -104,9 +147,10 @@
|
||||
|= =path
|
||||
^- (unit card)
|
||||
?> ?=([@ @ ~] path)
|
||||
=/ group-path (group-from-chat:cc path)
|
||||
=/ members (members-from-path:group group-path)
|
||||
?: (is-managed-path:group group-path) ~
|
||||
=/ group-paths (groups-of-chat:cc path)
|
||||
?~ group-paths ~
|
||||
=/ members (members-from-path:group i.group-paths)
|
||||
?: (is-managed-path:group i.group-paths) ~
|
||||
=/ ships=(set ship) (~(get ju subscribers) path)
|
||||
%- some
|
||||
=+ [%invite path (~(dif in members) ships)]
|
||||
@ -187,6 +231,17 @@
|
||||
^- (list (list card))
|
||||
(turn ~(tap in keys) generate-cards)
|
||||
==
|
||||
::
|
||||
++ scry-for
|
||||
|* [=mold app=term =path]
|
||||
.^ mold
|
||||
%gx
|
||||
(scot %p our.bol)
|
||||
app
|
||||
(scot %da now.bol)
|
||||
(snoc `^path`path %noun)
|
||||
==
|
||||
::
|
||||
++ kick-old-subs
|
||||
|= old-path=path
|
||||
^- (list card)
|
||||
@ -550,6 +605,7 @@
|
||||
::
|
||||
%add-synced
|
||||
?> (team:title our.bol src.bol)
|
||||
?< =(ship.act our.bol)
|
||||
?: (~(has by synced) path.act) [~ state]
|
||||
=. synced (~(put by synced) path.act ship.act)
|
||||
?. ask-history.act
|
||||
@ -816,13 +872,7 @@
|
||||
?: =(i.t.wir '~')
|
||||
?> ?=(^ chat)
|
||||
(migrate-listen t.chat)
|
||||
:_ state
|
||||
%. ~[(chat-view-poke %delete chat)]
|
||||
%- slog
|
||||
:* leaf+"chat-hook failed subscribe on {(spud chat)}"
|
||||
leaf+"stack trace:"
|
||||
u.saw
|
||||
==
|
||||
[~ state]
|
||||
==
|
||||
::
|
||||
++ chat-poke
|
||||
|
@ -5,7 +5,7 @@
|
||||
/- glob
|
||||
/+ default-agent, verb, dbug
|
||||
|%
|
||||
++ hash 0v5.6e3d0.3hm4q.iib09.rb2jb.9h4k4
|
||||
++ hash 0v6.k146g.ot3f9.d6vgi.6hrj7.4e5gn
|
||||
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
|
||||
+$ all-states
|
||||
$% state-0
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 693 B |
Binary file not shown.
Before Width: | Height: | Size: 582 B |
@ -24,7 +24,6 @@
|
||||
<div id="portal-root"></div>
|
||||
<script src="/~landscape/js/channel.js"></script>
|
||||
<script src="/~landscape/js/session.js"></script>
|
||||
<script src="/~landscape/js/bundle/index.9f00eb9b1c58d2b1bd3c.js"></script>
|
||||
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
|
||||
<script src="/~landscape/js/bundle/index.4c5a7f72912cc668f0e5.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -103,14 +103,16 @@ class Channel {
|
||||
path,
|
||||
connectionErrFunc = () => {},
|
||||
eventFunc = () => {},
|
||||
quitFunc = () => {}) {
|
||||
quitFunc = () => {},
|
||||
subAckFunc = () => {}) {
|
||||
let id = this.nextId();
|
||||
this.outstandingSubscriptions.set(
|
||||
id,
|
||||
{
|
||||
err: connectionErrFunc,
|
||||
event: eventFunc,
|
||||
quit: quitFunc
|
||||
quit: quitFunc,
|
||||
subAck: subAckFunc
|
||||
}
|
||||
);
|
||||
|
||||
@ -205,11 +207,12 @@ class Channel {
|
||||
} else if (obj.response == "subscribe" ||
|
||||
(obj.response == "poke" && !!subFuncs)) {
|
||||
let funcs = subFuncs;
|
||||
// on a response to a subscribe, we only notify the caller on err
|
||||
//
|
||||
|
||||
if (obj.hasOwnProperty("err")) {
|
||||
funcs["err"](obj.err);
|
||||
this.outstandingSubscriptions.delete(obj.id);
|
||||
} else if (obj.hasOwnProperty("ok")) {
|
||||
funcs["subAck"](obj);
|
||||
}
|
||||
} else if (obj.response == "diff") {
|
||||
let funcs = subFuncs;
|
||||
|
@ -56,25 +56,27 @@
|
||||
+$ state-2 [%2 base-state-0]
|
||||
+$ state-3 [%3 base-state-1]
|
||||
+$ state-4 [%4 base-state-1]
|
||||
+$ state-5 [%5 base-state-1]
|
||||
+$ versioned-state
|
||||
$% state-0
|
||||
state-1
|
||||
state-2
|
||||
state-3
|
||||
state-4
|
||||
state-5
|
||||
==
|
||||
--
|
||||
::
|
||||
=| state-4
|
||||
=| state-5
|
||||
=* state -
|
||||
%+ verb |
|
||||
%- agent:dbug
|
||||
^- agent:gall
|
||||
=<
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
mc ~(. +> bowl)
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
+* this .
|
||||
mc ~(. +> bowl)
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
::
|
||||
++ on-init on-init:def
|
||||
++ on-save !>(state)
|
||||
@ -84,21 +86,32 @@
|
||||
=/ old !<(versioned-state vase)
|
||||
=| cards=(list card)
|
||||
|^
|
||||
?: ?=(%4 -.old)
|
||||
?: ?=(%5 -.old)
|
||||
[cards this(state old)]
|
||||
?: ?=(%3 -.old)
|
||||
%_ $
|
||||
-.old %4
|
||||
::
|
||||
resource-indices.old
|
||||
(rebuild-resource-indices associations.old)
|
||||
::
|
||||
app-indices.old
|
||||
(rebuild-app-indices associations.old)
|
||||
::
|
||||
?: ?=(%4 -.old)
|
||||
%_ $
|
||||
-.old %5
|
||||
::
|
||||
group-indices.old
|
||||
(rebuild-group-indices associations.old)
|
||||
%- ~(gas ju *(jug group-path md-resource))
|
||||
~(tap in ~(key by associations.old))
|
||||
::
|
||||
app-indices.old
|
||||
%- ~(gas ju *(jug app-name [group-path app-path]))
|
||||
%+ turn ~(tap in ~(key by associations.old))
|
||||
|= [g=group-path r=md-resource]
|
||||
^- [app-name [group-path app-path]]
|
||||
[app-name.r [g app-path.r]]
|
||||
::
|
||||
resource-indices.old
|
||||
%- ~(gas ju *(jug md-resource group-path))
|
||||
%+ turn ~(tap in ~(key by associations.old))
|
||||
|= [g=group-path r=md-resource]
|
||||
^- [md-resource group-path]
|
||||
[r g]
|
||||
==
|
||||
?: ?=(%3 -.old)
|
||||
$(old [%4 +.old])
|
||||
?: ?=(%2 -.old)
|
||||
=/ new-state=state-3
|
||||
%* . *state-3
|
||||
@ -134,41 +147,6 @@
|
||||
==
|
||||
$(old new-state-1)
|
||||
::
|
||||
++ rebuild-app-indices
|
||||
=| app-indices=(jug app-name [group-path app-path])
|
||||
|= =^associations
|
||||
^- (jug app-name [group-path app-path])
|
||||
?~ associations app-indices
|
||||
=. app-indices
|
||||
%+ ~(put ju app-indices) app-name.p.n.associations
|
||||
[-.p.n.associations app-path.p.n.associations]
|
||||
%- ~(uni by $(associations l.associations))
|
||||
$(associations r.associations)
|
||||
::
|
||||
++ rebuild-group-indices
|
||||
=| group-indices=(jug group-path md-resource)
|
||||
|= =^associations
|
||||
^- (jug group-path md-resource)
|
||||
?~ associations group-indices
|
||||
=. group-indices
|
||||
%+ ~(put ju group-indices)
|
||||
-.p.n.associations
|
||||
+.p.n.associations
|
||||
%- ~(uni by $(associations l.associations))
|
||||
$(associations r.associations)
|
||||
::
|
||||
++ rebuild-resource-indices
|
||||
=| resource-indices=(jug md-resource group-path)
|
||||
|= =^associations
|
||||
^- (jug md-resource group-path)
|
||||
?~ associations resource-indices
|
||||
=. resource-indices
|
||||
%+ ~(put ju resource-indices)
|
||||
+.p.n.associations
|
||||
-.p.n.associations
|
||||
%- ~(uni by $(associations l.associations))
|
||||
$(associations r.associations)
|
||||
::
|
||||
++ poke-md-hook
|
||||
|= act=metadata-hook-action
|
||||
^- card
|
||||
|
@ -164,7 +164,7 @@
|
||||
~(tap in ~(key by starting.any))
|
||||
|- ^- (quip card _this)
|
||||
?~ yarns
|
||||
`this
|
||||
[~[bind-eyre:sc] this]
|
||||
=^ cards-1 state
|
||||
(handle-stop-thread:sc (yarn-to-tid i.yarns) |)
|
||||
=^ cards-2 this
|
||||
|
@ -243,7 +243,10 @@
|
||||
%+ rose (tufa buf.cli-state)
|
||||
(command-parser:og sole-id)
|
||||
?: ?=(%& -.res)
|
||||
?. &(?=(^ p.res) run.u.p.res)
|
||||
:: only auto-run eligible commands if they were typed out
|
||||
:: (that is, not retrieved from command history)
|
||||
::
|
||||
?. &(?=(^ p.res) run.u.p.res !?=(%set -.ted.sole-change))
|
||||
[[~ cli-state] shoe]
|
||||
(run-command cmd.u.p.res)
|
||||
:_ shoe
|
||||
|
@ -10,11 +10,12 @@ applications. Landscape applications will usually make good use of Gall, but
|
||||
it's not strictly required if a Landscape application is not interacting with
|
||||
ships directly.
|
||||
|
||||
## Contributing to Landscape applications
|
||||
## Starting the dev environment
|
||||
|
||||
To begin developing on Landscape, find the `urbitrc-sample` file found
|
||||
at `urbit/pkg/interface/config/urbitrc-sample`. Copy it as `urbitrc`.
|
||||
Open it using your preferred code editor and you should see the following:
|
||||
From this directory, go to the config folder and copy `urbitrc-sample` to
|
||||
`urbitrc`.
|
||||
|
||||
You should see the following:
|
||||
|
||||
```
|
||||
module.exports = {
|
||||
@ -26,130 +27,17 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
This file is the configuration file for your front-end development environment.
|
||||
Let's walk through it.
|
||||
|
||||
The first line, listing piers, specifies which piers to copy the JS files into.
|
||||
By default, the development environment won't copy files into any pier, even if
|
||||
you've set the pier in `urbitrc`.
|
||||
|
||||
If you want to copy the JS files into your ship, as it would run in a regular
|
||||
user environment, uncomment these lines in
|
||||
`pkg/interface/config/webpack.dev.js`:
|
||||
|
||||
```javascript
|
||||
// uncomment to copy into all piers
|
||||
//
|
||||
// return Promise.all(this.piers.map(pier => {
|
||||
// const dst = path.resolve(pier, 'app/landscape/js/index.js');
|
||||
// copyFile(src, dst).then(() => {
|
||||
// if(!this.herb) {
|
||||
// return;
|
||||
// }
|
||||
// pier = pier.split('/');
|
||||
// const desk = pier.pop();
|
||||
// return exec(`herb -p hood -d '+hood/commit %${desk}' ${pier.join('/')}`);
|
||||
// });
|
||||
// }));
|
||||
```
|
||||
|
||||
And then set your pier in `urbitrc` (ensure it ends in `/home`). The `herb`
|
||||
option in your `urbitrc` will automatically commit the changes to your ship if
|
||||
you have herb installed (see `pkg/herb`).
|
||||
|
||||
For most developers, if you are making changes to Landscape without any back-end
|
||||
changes on the Urbit ship itself, and you have an Urbit ship running already,
|
||||
you don't have to boot a development ship. You can simply set up the dev server
|
||||
for the development environment and point it at your running ship.
|
||||
|
||||
To do this, set the `URL` property in your urbitrc and replace it with the URL
|
||||
of the urbit that you are testing on. For example, a development ship by default
|
||||
lives at `localhost:80` so our `urbitrc` would have:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
URL: 'http://localhost:80'
|
||||
}
|
||||
```
|
||||
|
||||
Then get everything installed:
|
||||
Change the URL to your livenet ship (if making front-end changes) or keep it the
|
||||
same (if [developing on a local development ship][local]). Then, from
|
||||
'pkg/interface':
|
||||
|
||||
```
|
||||
## go to urbit's interface directory and install the required tooling
|
||||
cd urbit/pkg/interface
|
||||
npm install
|
||||
|
||||
## Start your development server
|
||||
npm run start
|
||||
```
|
||||
|
||||
You can then access a hot reloaded version of the interface at
|
||||
`http://localhost:9000`.
|
||||
|
||||
If you set the URL to your running ship, like
|
||||
`http://sampel-palnet.arvo.network`, then you can use your actual ship while
|
||||
running local-only development changes.
|
||||
|
||||
As previously stated, if your changes require back-end development (front-end
|
||||
and Gall changes, for example), or you just want an empty development
|
||||
environment, you'll want to create a development ship.
|
||||
|
||||
### Creating a development ship
|
||||
|
||||
[nix](https://github.com/NixOS/nix) and `git-lfs` should be installed at this
|
||||
point, and have been used to `make build` the project.
|
||||
|
||||
First follow the
|
||||
[instructions](https://urbit.org/using/develop/#creating-a-development-ship) for
|
||||
fake `~zod` initialization.
|
||||
|
||||
Once your fake ship is running and you see
|
||||
```
|
||||
~zod:dojo>
|
||||
```
|
||||
in your console, be sure to 'mount' your ship's working state (what we call
|
||||
'desks') to your local machine via the `|mount %` command. This will ensure that
|
||||
code you modify locally can be committed to your ship and initialized.
|
||||
|
||||
To set up urbit's Javascript environment, you'll need node (ideally installed
|
||||
via [nvm](https://github.com/nvm-sh/nvm)) and webpack, which will be installed
|
||||
via node.
|
||||
|
||||
If you want to copy the code into your ship, perform the following steps:
|
||||
|
||||
```
|
||||
## go to urbit's interface directory and install the required tooling
|
||||
cd urbit/pkg/interface
|
||||
npm install
|
||||
|
||||
## Build the JS code
|
||||
npm run build:dev
|
||||
```
|
||||
|
||||
If you want to run the JavaScript code in a dev server, you can simply set the
|
||||
URL in your `urbitrc` to `localhost:80` and `npm run start` instead.
|
||||
|
||||
If you set your pier in `urbitrc`, and uncommented the code in the webpack
|
||||
config, then once the build process is running, commit on your ship to copy the
|
||||
changed JS code in:
|
||||
|
||||
```
|
||||
|commit %home
|
||||
```
|
||||
|
||||
Your urbit should take a moment to process the changes, and will emit a `>=`.
|
||||
Refreshing your browser will display the newly-rendered interface.
|
||||
|
||||
Once you are done editing code, and wish to commit changes to git, stop your
|
||||
process. Do not commit compiled code, but submit the source code
|
||||
for review.
|
||||
|
||||
Please also ensure your pull request fits our standards for [Git
|
||||
hygiene][contributing].
|
||||
|
||||
[contributing]: /CONTRIBUTING.md#git-practice
|
||||
[arvo]: /pkg/arvo
|
||||
[interface]:/pkg/interface
|
||||
The dev server will start at `http://localhost:9000`. Sign in as you would
|
||||
normally. Landscape will refresh automatically as you make changes.
|
||||
|
||||
## Linting
|
||||
|
||||
@ -170,12 +58,6 @@ $ npm run lint-file ./src/apps/chat/**/*.js # lints all .js files in `interface/
|
||||
$ npm run lint-file ./src/chat/app.js # lints a single chosen file
|
||||
```
|
||||
|
||||
### Gall
|
||||
|
||||
Presently, Gall documentation is still in [progress][gall], but a good
|
||||
reference. For examples of Landscape apps that use Gall, see the code for
|
||||
[Chat][chat] and [Publish][publish].
|
||||
|
||||
## Creating your own applications
|
||||
|
||||
If you'd like to create your own application for Landscape, the easiest way to
|
||||
@ -188,5 +70,4 @@ running.
|
||||
[cla]: https://github.com/urbit/create-landscape-app
|
||||
[template]: https://github.com/urbit/create-landscape-app/generate
|
||||
[gall]:https://urbit.org/docs/learn/arvo/gall/
|
||||
[chat]: /pkg/arvo/app/chat-view.hoon
|
||||
[publish]: /pkg/arvo/app/publish.hoon
|
||||
[local]: /CONTRIBUTING.md#fake-ships
|
@ -52,7 +52,7 @@ const appIndex = function (apps) {
|
||||
});
|
||||
// add groups separately
|
||||
applications.push(
|
||||
result('Groups', '/~groups', 'groups', null)
|
||||
result('Groups', '/~groups', 'Groups', null)
|
||||
);
|
||||
return [];
|
||||
return applications;
|
||||
|
@ -17,6 +17,7 @@ import dark from './themes/old-dark';
|
||||
import { Content } from './components/Content';
|
||||
import StatusBar from './components/StatusBar';
|
||||
import Omnibox from './components/leap/Omnibox';
|
||||
import ErrorBoundary from '~/views/components/ErrorBoundary';
|
||||
|
||||
import GlobalStore from '~/logic/store/store';
|
||||
import GlobalSubscription from '~/logic/subscription/global';
|
||||
@ -132,28 +133,34 @@ class App extends React.Component {
|
||||
</Helmet>
|
||||
<Root background={background} >
|
||||
<Router>
|
||||
<StatusBarWithRouter
|
||||
props={this.props}
|
||||
associations={associations}
|
||||
invites={this.state.invites}
|
||||
api={this.api}
|
||||
connection={this.state.connection}
|
||||
subscription={this.subscription}
|
||||
ship={this.ship}
|
||||
/>
|
||||
<Omnibox
|
||||
associations={state.associations}
|
||||
apps={state.launch}
|
||||
api={this.api}
|
||||
dark={state.dark}
|
||||
show={state.omniboxShown}
|
||||
/>
|
||||
<Content
|
||||
ship={this.ship}
|
||||
api={this.api}
|
||||
subscription={this.subscription}
|
||||
{...state}
|
||||
/>
|
||||
<ErrorBoundary>
|
||||
<StatusBarWithRouter
|
||||
props={this.props}
|
||||
associations={associations}
|
||||
invites={this.state.invites}
|
||||
api={this.api}
|
||||
connection={this.state.connection}
|
||||
subscription={this.subscription}
|
||||
ship={this.ship}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
<ErrorBoundary>
|
||||
<Omnibox
|
||||
associations={state.associations}
|
||||
apps={state.launch}
|
||||
api={this.api}
|
||||
dark={state.dark}
|
||||
show={state.omniboxShown}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
<ErrorBoundary>
|
||||
<Content
|
||||
ship={this.ship}
|
||||
api={this.api}
|
||||
subscription={this.subscription}
|
||||
{...state}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</Router>
|
||||
</Root>
|
||||
<div id="portal-root" />
|
||||
|
@ -160,12 +160,9 @@ export default class ChatInput extends Component<ChatInputProps, ChatInputState>
|
||||
}
|
||||
if (!this.s3Uploader.current || !this.s3Uploader.current.inputRef.current) return;
|
||||
this.s3Uploader.current.inputRef.current.files = files;
|
||||
setTimeout(() => {
|
||||
if (this.s3Uploader.current.state.isUploading) return;
|
||||
const fire = document.createEvent("HTMLEvents");
|
||||
fire.initEvent("change", true, true);
|
||||
this.s3Uploader.current?.inputRef.current?.dispatchEvent(fire);
|
||||
}, 200);
|
||||
const fire = document.createEvent("HTMLEvents");
|
||||
fire.initEvent("change", true, true);
|
||||
this.s3Uploader.current?.inputRef.current?.dispatchEvent(fire);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -30,7 +30,7 @@ export class GroupifyButton extends Component {
|
||||
return this.state.targetGroup ? (
|
||||
<Box mt='4'>
|
||||
<Toggle
|
||||
boolean={inclusive}
|
||||
boolean={this.state.inclusive}
|
||||
change={this.changeInclusive.bind(this)}
|
||||
/>
|
||||
<Text display='inline-block' fontSize='0' ml='3'>
|
||||
@ -52,7 +52,8 @@ export class GroupifyButton extends Component {
|
||||
associations,
|
||||
contacts,
|
||||
groups,
|
||||
station
|
||||
station,
|
||||
changeLoading
|
||||
} = this.props;
|
||||
|
||||
const groupPath = association['group-path'];
|
||||
|
@ -52,7 +52,7 @@ export class NewDmScreen extends Component {
|
||||
|
||||
titleChange(event) {
|
||||
const asciiSafe = event.target.value.toLowerCase()
|
||||
.replace(/[^a-z0-9~_.-]/g, '-');
|
||||
.replace(/[^a-z0-9_-]/g, '-');
|
||||
this.setState({
|
||||
idName: asciiSafe,
|
||||
title: event.target.value
|
||||
|
@ -38,7 +38,7 @@ export class NewScreen extends Component {
|
||||
|
||||
titleChange(event) {
|
||||
const asciiSafe = event.target.value.toLowerCase()
|
||||
.replace(/[^a-z0-9~_.-]/g, '-');
|
||||
.replace(/[^a-z0-9_-]/g, '-');
|
||||
this.setState({
|
||||
idName: asciiSafe,
|
||||
title: event.target.value
|
||||
|
@ -83,6 +83,7 @@ export class SettingsScreen extends Component {
|
||||
contacts={contacts}
|
||||
groups={groups}
|
||||
api={api}
|
||||
station={station}
|
||||
changeLoading={this.changeLoading} />
|
||||
<DeleteButton
|
||||
isOwner={isOwner}
|
||||
|
@ -6,8 +6,8 @@ import { Spinner } from '~/views/components/Spinner';
|
||||
import { Toggle } from '~/views/components/toggle';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { Groups, GroupPolicy, Resource } from '~/types/group-update';
|
||||
import { Contacts, Rolodex } from '~/types/contact-update';
|
||||
import { Groups, GroupPolicy } from '~/types/group-update';
|
||||
import { Rolodex } from '~/types/contact-update';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { Patp, PatpNoSig, Enc } from '~/types/noun';
|
||||
import {Body} from '~/views/components/Body';
|
||||
@ -21,7 +21,6 @@ type NewScreenProps = Pick<RouteComponentProps, 'history'> & {
|
||||
type TextChange = React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>;
|
||||
type BooleanChange = React.ChangeEvent<HTMLInputElement>;
|
||||
|
||||
|
||||
interface NewScreenState {
|
||||
groupName: string;
|
||||
title: string;
|
||||
@ -56,7 +55,7 @@ export class NewScreen extends Component<NewScreenProps, NewScreenState> {
|
||||
groupNameChange(event: TextChange) {
|
||||
const asciiSafe = event.target.value
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9~_.-]/g, '-');
|
||||
.replace(/[^a-z0-9_-]/g, '-');
|
||||
this.setState({
|
||||
groupName: asciiSafe,
|
||||
title: event.target.value,
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React, { Component, useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { TabBar } from '~/views/components/chat-link-tabbar';
|
||||
import { LinkPreview } from './lib/link-preview';
|
||||
import { LinkSubmit } from './lib/link-submit';
|
||||
import { CommentSubmit } from './lib/comment-submit';
|
||||
import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Comments } from './lib/comments';
|
||||
import { getContactDetails } from '~/logic/lib/util';
|
||||
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
|
||||
export const LinkDetail = (props) => {
|
||||
if (!props.node && props.graphResource) {
|
||||
@ -29,37 +29,42 @@ export const LinkDetail = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const { nickname } = getContactDetails(props.contacts[ship]);
|
||||
const our = getContactDetails(props.contacts[window.ship]);
|
||||
const { nickname } = getContactDetails(props.contacts[props.node?.post?.author]);
|
||||
const resourcePath = `${props.ship}/${props.name}`;
|
||||
const title = props.resource.metadata.title || resourcePath;
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-hidden flex flex-column">
|
||||
<div
|
||||
className={
|
||||
'pl4 pt2 flex relative overflow-x-scroll ' +
|
||||
'overflow-x-auto-l overflow-x-auto-xl flex-shrink-0 ' +
|
||||
'bb bn-m bn-l bn-xl b--gray4'
|
||||
}
|
||||
style={{ height: 48 }}>
|
||||
<Box
|
||||
pl='12px'
|
||||
pt='2'
|
||||
display='flex'
|
||||
position='relative'
|
||||
overflowX={['scroll', 'auto']}
|
||||
flexShrink='0'
|
||||
borderBottom='1px solid'
|
||||
borderColor='washedGray'
|
||||
height='48px'
|
||||
>
|
||||
<SidebarSwitcher
|
||||
sidebarShown={props.sidebarShown}
|
||||
api={props.api}
|
||||
/>
|
||||
<Link className="dib f9 fw4 pt2 gray2 lh-solid"
|
||||
to={`/~link/${resourcePath}`}>
|
||||
to={`/~link/${resourcePath}`}
|
||||
>
|
||||
<h2
|
||||
className="dib f9 fw4 lh-solid v-top black white-d"
|
||||
style={{ width: 'max-content' }}>
|
||||
{`<- ${title}`}
|
||||
style={{ width: 'max-content' }}
|
||||
>
|
||||
{`${title}`}
|
||||
</h2>
|
||||
</Link>
|
||||
<TabBar
|
||||
location={props.location}
|
||||
settings={`/~link/${resourcePath}/settings`}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
|
||||
<div className="w-100 mw7">
|
||||
<LinkPreview
|
||||
@ -75,7 +80,8 @@ export const LinkDetail = (props) => {
|
||||
name={props.name}
|
||||
ship={props.ship}
|
||||
api={props.api}
|
||||
parentIndex={props.node.post.index} />
|
||||
parentIndex={props.node.post.index}
|
||||
/>
|
||||
</div>
|
||||
<Comments
|
||||
comments={props.node.children}
|
||||
@ -84,10 +90,11 @@ export const LinkDetail = (props) => {
|
||||
api={props.api}
|
||||
hideAvatars={props.hideAvatars}
|
||||
hideNicknames={props.hideNicknames}
|
||||
remoteContentPolicy={props.remoteContentPolicy} />
|
||||
remoteContentPolicy={props.remoteContentPolicy}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { LinkItem } from './lib/link-item';
|
||||
import LinkSubmit from './lib/link-submit';
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
|
||||
import { getContactDetails } from "~/logic/lib/util";
|
||||
|
||||
@ -34,14 +35,16 @@ export const LinkList = (props) => {
|
||||
>
|
||||
<Link to="/~link">{"⟵ All Channels"}</Link>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
"pl4 pt2 flex relative overflow-x-scroll" +
|
||||
"overflow-x-auto-l overflow-x-auto-xl flex-shrink-0" +
|
||||
"bb b--gray4 b--gray1-d bg-gray0-d"
|
||||
}
|
||||
style={{ height: 48 }}
|
||||
>
|
||||
<Box
|
||||
pl='12px'
|
||||
pt='2'
|
||||
display='flex'
|
||||
position='relative'
|
||||
overflowX={['scroll', 'auto']}
|
||||
flexShrink='0'
|
||||
borderBottom='1px solid'
|
||||
borderColor='washedGray'
|
||||
height='48px'>
|
||||
<SidebarSwitcher
|
||||
sidebarShown={props.sidebarShown}
|
||||
api={props.api} />
|
||||
@ -54,7 +57,7 @@ export const LinkList = (props) => {
|
||||
location={props.location}
|
||||
settings={`/~link/${resource}/settings`}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
<div className="w-100 mt6 flex justify-center overflow-y-scroll ph4 pb4">
|
||||
<div className="w-100 mw7">
|
||||
<div className="flex">
|
||||
@ -66,10 +69,10 @@ export const LinkList = (props) => {
|
||||
</div>
|
||||
{ Array.from(props.graph).map(([date, node]) => {
|
||||
const { nickname, color, avatar } =
|
||||
getContactDetails(props.contacts[ship]);
|
||||
|
||||
getContactDetails(props.contacts[node?.post?.author]);
|
||||
return (
|
||||
<LinkItem
|
||||
key={date}
|
||||
resource={resource}
|
||||
node={node}
|
||||
nickname={nickname}
|
||||
|
@ -7,6 +7,8 @@ import { Spinner } from '~/views/components/Spinner';
|
||||
import { TabBar } from '~/views/components/chat-link-tabbar';
|
||||
import SidebarSwitcher from '~/views/components/SidebarSwitch';
|
||||
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
|
||||
import { MetadataSettings } from '~/views/components/metadata/settings';
|
||||
|
||||
import { Box, Text, Button, Col, Row } from '@tlon/indigo-react';
|
||||
|
@ -63,6 +63,7 @@ export function MarkdownEditor(
|
||||
{...boxProps}
|
||||
>
|
||||
<CodeEditor
|
||||
autoCursor={false}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
options={options}
|
||||
|
@ -10,7 +10,6 @@ import { Sigil } from '~/logic/lib/sigil';
|
||||
const StatusBar = (props) => {
|
||||
|
||||
const location = useLocation();
|
||||
const atHome = Boolean(location.pathname === '/');
|
||||
|
||||
const invites = (props.invites && props.invites['/contacts'])
|
||||
? props.invites['/contacts']
|
||||
@ -30,17 +29,10 @@ const StatusBar = (props) => {
|
||||
>
|
||||
<Row collapse>
|
||||
<StatusBarItem mr={2} onClick={() => props.history.push('/')}>
|
||||
<img
|
||||
className='invert-d'
|
||||
src='/~landscape/img/icon-home.png'
|
||||
height='11'
|
||||
width='11'
|
||||
/>
|
||||
<Icon icon='Home' color='transparent' stroke='black' />
|
||||
</StatusBarItem>
|
||||
<StatusBarItem mr={2} onClick={() => props.api.local.setOmnibox()}>
|
||||
<Text display='inline-block' style={{ transform: 'rotate(180deg)' }}>
|
||||
↩
|
||||
</Text>
|
||||
<Icon icon='LeapArrow'/>
|
||||
<Text ml={2} color='black'>
|
||||
Leap
|
||||
</Text>
|
||||
|
@ -31,10 +31,8 @@ export function StatusBarItem({
|
||||
<Icon
|
||||
size="22px"
|
||||
icon="Bullet"
|
||||
fill="blue"
|
||||
position="absolute"
|
||||
top={"-10px"}
|
||||
right={"-12px"}
|
||||
color="blue"
|
||||
style={{ position: 'absolute', top: '-10', right: '-11' }}
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
|
@ -26,43 +26,22 @@ export class OmniboxResult extends Component {
|
||||
}
|
||||
|
||||
getIcon(icon, dark, selected, link) {
|
||||
// graphicStyle is only necessary for pngs
|
||||
//
|
||||
//TODO can be removed after indigo-react 1.2
|
||||
//which includes icons for apps
|
||||
let graphicStyle = {};
|
||||
|
||||
if (icon.toLowerCase() !== 'dojo') {
|
||||
graphicStyle = (!dark && this.state.hovered) ||
|
||||
selected === link ||
|
||||
(dark && !(this.state.hovered || selected === link))
|
||||
? { filter: 'invert(1)' }
|
||||
: { filter: 'invert(0)' };
|
||||
} else {
|
||||
graphicStyle =
|
||||
(!dark && this.state.hovered) ||
|
||||
selected === link ||
|
||||
(dark && !(this.state.hovered || selected === link))
|
||||
? { filter: 'invert(0)' }
|
||||
: { filter: 'invert(1)' };
|
||||
}
|
||||
|
||||
const iconFill = this.state.hovered || selected === link ? 'white' : 'black';
|
||||
const sigilFill = this.state.hovered || selected === link ? '#3a8ff7' : '#ffffff';
|
||||
const iconFill = (this.state.hovered || (selected === link)) ? 'white' : 'black';
|
||||
const sigilFill = (this.state.hovered || (selected === link)) ? '#3a8ff7' : '#ffffff';
|
||||
|
||||
let graphic = <div />;
|
||||
if (defaultApps.includes(icon.toLowerCase()) || icon.toLowerCase() === 'links') {
|
||||
graphic =
|
||||
<img className="mr2 v-mid dib" height="16"
|
||||
width="16" src={`/~landscape/img/${icon.toLowerCase()}.png`}
|
||||
style={graphicStyle}
|
||||
/>;
|
||||
icon = (icon === 'Dojo') ? 'ChevronEast' : icon;
|
||||
icon = (icon === 'Link') ? 'Links' : icon;
|
||||
const color = (icon === 'ChevronEast') ? iconFill : 'transparent';
|
||||
const stroke = (icon === 'ChevronEast') ? 'transparent' : iconFill;
|
||||
graphic = <Icon display="inline-block" verticalAlign="middle" icon={icon} mr='2' size='16px' color={color} stroke={stroke} />;
|
||||
} else if (icon === 'logout') {
|
||||
graphic = <Icon display="inline-block" verticalAlign="middle" icon='ArrowWest' mr='2' size='16px' fill={iconFill} />;
|
||||
graphic = <Icon display="inline-block" verticalAlign="middle" icon='ArrowWest' mr='2' size='16px' color={iconFill} />;
|
||||
} else if (icon === 'profile') {
|
||||
graphic = <Sigil color={sigilFill} classes='dib v-mid mr2' ship={window.ship} size={16} />;
|
||||
} else {
|
||||
graphic = <Icon verticalAlign="middle" mr='2' size="16px" fill={iconFill} />;
|
||||
graphic = <Icon verticalAlign="middle" mr='2' size="16px" color={iconFill} />;
|
||||
}
|
||||
|
||||
return graphic;
|
||||
@ -78,68 +57,40 @@ export class OmniboxResult extends Component {
|
||||
const graphic = this.getIcon(icon, dark, selected, link);
|
||||
|
||||
return (
|
||||
<Row
|
||||
py='2'
|
||||
px='2'
|
||||
display='flex'
|
||||
flexDirection='row'
|
||||
style={{ cursor: 'pointer' }}
|
||||
onMouseEnter={() => this.setHover(true)}
|
||||
onMouseLeave={() => this.setHover(false)}
|
||||
backgroundColor={
|
||||
this.state.hovered || selected === link ? 'blue' : 'white'
|
||||
}
|
||||
onClick={navigate}
|
||||
width="100%"
|
||||
ref={this.result}
|
||||
<Row
|
||||
py='2'
|
||||
px='2'
|
||||
cursor='pointer'
|
||||
onMouseEnter={() => this.setHover(true)}
|
||||
onMouseLeave={() => this.setHover(false)}
|
||||
backgroundColor={
|
||||
this.state.hovered || selected === link ? 'blue' : 'white'
|
||||
}
|
||||
onClick={navigate}
|
||||
width="100%"
|
||||
ref={this.result}
|
||||
>
|
||||
{graphic}
|
||||
<Text
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
color={this.state.hovered || selected === link ? 'white' : 'black'}
|
||||
maxWidth="60%"
|
||||
style={{ flexShrink: 0 }}
|
||||
mr='1'
|
||||
>
|
||||
{this.state.hovered || selected === link ? (
|
||||
<>
|
||||
{graphic}
|
||||
<Text
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
color='white'
|
||||
maxWidth="60%"
|
||||
style={{ flexShrink: 0 }}
|
||||
mr='1'>
|
||||
{text}
|
||||
</Text>
|
||||
<Text pr='2'
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
color='white'
|
||||
width='100%'
|
||||
textAlign='right'
|
||||
>
|
||||
{subtext}
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{graphic}
|
||||
<Text
|
||||
mr='1'
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
maxWidth="60%"
|
||||
style={{ flexShrink: 0 }}
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
<Text
|
||||
pr='2'
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
gray
|
||||
width='100%'
|
||||
textAlign='right'
|
||||
>
|
||||
{subtext}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Row>
|
||||
{text}
|
||||
</Text>
|
||||
<Text pr='2'
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
color={this.state.hovered || selected === link ? 'white' : 'black'}
|
||||
width='100%'
|
||||
textAlign='right'
|
||||
>
|
||||
{subtext}
|
||||
</Text>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ export const MetadataSettings = (props) => {
|
||||
val,
|
||||
association.metadata.description,
|
||||
association.metadata['date-created'],
|
||||
module,
|
||||
uxToHex(association.metadata.color)
|
||||
uxToHex(association.metadata.color),
|
||||
module
|
||||
).then(() => {
|
||||
changeLoading(false, false, '', () => {});
|
||||
});
|
||||
|
@ -99,22 +99,25 @@ export class S3Upload extends Component<S3UploadProps, S3UploadState> {
|
||||
const timestamp = deSig(dateToDa(new Date()));
|
||||
let bucket = props.configuration.currentBucket;
|
||||
|
||||
this.setState({ isUploading: true });
|
||||
setTimeout(() => {
|
||||
if (this.state.isUploading) return;
|
||||
this.setState({ isUploading: true });
|
||||
this.s3.upload(bucket, `${window.ship}/${timestamp}-${fileName}.${fileExtension}`, file)
|
||||
.then((data) => {
|
||||
if (!data || !('Location' in data)) {
|
||||
return;
|
||||
}
|
||||
this.props.uploadSuccess(data.Location);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
this.props.uploadError(err);
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isUploading: false });
|
||||
});
|
||||
}, 200);
|
||||
|
||||
this.s3.upload(bucket, `${window.ship}/${timestamp}-${fileName}.${fileExtension}`, file)
|
||||
.then((data) => {
|
||||
if (!data || !('Location' in data)) {
|
||||
return;
|
||||
}
|
||||
this.props.uploadSuccess(data.Location);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
this.props.uploadError(err);
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isUploading: false });
|
||||
});
|
||||
}
|
||||
|
||||
onClick() {
|
||||
|
Loading…
Reference in New Issue
Block a user