Merge branch 'release/next-userspace' into lf/global-skeleton-links

This commit is contained in:
Liam Fitzgerald 2020-10-05 15:47:45 +10:00
commit bda2770320
32 changed files with 284 additions and 394 deletions

View File

@ -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.

View File

@ -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

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:eab360913b845f8775002cfe1830defcd252b490ac90e8dfa093297b56531392
size 19090656
oid sha256:b1ae413b0ac4cc6ddd4f4e7e380852171a4b28436e1c4bff693425c3acbca473
size 6229799

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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" />

View File

@ -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() {

View File

@ -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'];

View File

@ -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

View File

@ -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

View File

@ -83,6 +83,7 @@ export class SettingsScreen extends Component {
contacts={contacts}
groups={groups}
api={api}
station={station}
changeLoading={this.changeLoading} />
<DeleteButton
isOwner={isOwner}

View File

@ -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,

View File

@ -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>
);
}
};

View File

@ -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}

View File

@ -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';

View File

@ -63,6 +63,7 @@ export function MarkdownEditor(
{...boxProps}
>
<CodeEditor
autoCursor={false}
onBlur={onBlur}
value={value}
options={options}

View File

@ -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>

View File

@ -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>

View File

@ -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>
);
}
}

View File

@ -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, '', () => {});
});

View File

@ -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() {