Merge branch 'release/next-userspace' into mp/links-indigo

This commit is contained in:
Matilde Park 2020-08-19 18:23:11 -04:00
commit 2c621caac2
117 changed files with 614 additions and 533 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ef417c3092dc32d6d5897a7ba63f3f8910f928f0aa23adf3a356b88ce027a415
size 6260173
oid sha256:6cd7246753c12c7acb757e1a6ee54c177806c20a137ad8fb4300c000ac146a0f
size 6260139

View File

@ -164,10 +164,7 @@
(fact-group-update:cc wire !<(update:group-store q.cage.sign))
[cards this]
::
%invite-update
=^ cards state
(fact-invite-update:cc wire !<(invite-update q.cage.sign))
[cards this]
%invite-update [~ this]
==
==
::
@ -481,17 +478,6 @@
[%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)]
--
::
++ fact-invite-update
|= [wir=wire fact=invite-update]
^- (quip card _state)
?+ -.fact [~ state]
%accepted
=/ rid=resource
(de-path:resource path.invite.fact)
:_ state
~[(contact-view-poke %join rid)]
==
::
++ group-hook-poke
|= =action:group-hook
^- card

View File

@ -153,9 +153,13 @@
=* headers header-list.req
=/ req-line (parse-request-line url.req)
?. =(method.req %'GET') not-found:gen
=. site.req-line
%+ murn site.req-line
|= =cord
^- (unit ^cord)
?:(=(cord '') ~ `cord)
=? req-line ?=(~ ext.req-line)
[[[~ %html] ~['index']] args.req-line]
?> ?=(^ ext.req-line)
[[[~ %html] (snoc site.req-line 'index')] args.req-line]
?~ site.req-line
not-found:gen
=* url-prefix landscape-homepage-prefix.configuration
@ -177,7 +181,9 @@
++ get-file
|= req-line=request-line
^- [simple-payload:http ?]
=/ pax=path (snoc site.req-line (need ext.req-line))
=/ pax=path
?~ ext.req-line site.req-line
(snoc site.req-line u.ext.req-line)
=/ content=(unit [=content suffix=path public=?]) (get-content pax)
?~ content [not-found:gen %.n]
?- -.content.u.content

View File

@ -1,7 +1,7 @@
/- glob
/+ default-agent, verb, dbug
|%
++ hash 0v7.foe2o.ang8k.28dnr.fudi0.74c8d
++ hash 0v2.pbthv.gd1q2.h2ura.5esrn.d361c
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
+$ all-states
$% state-0

View File

@ -227,8 +227,11 @@
++ peek-group-join
|= [rid=resource =ship]
=/ =group
(~(gut by groups) rid *group)
=/ ugroup
(~(get by groups) rid)
?~ ugroup
%.n
=* group u.ugroup
=* policy policy.group
?- -.policy
%invite

View File

@ -23,7 +23,7 @@
<div id="root"></div>
<script src="/~landscape/js/channel.js"></script>
<script src="/~landscape/js/session.js"></script>
<script src="/~landscape/js/bundle/index.8e25dc41456a44c967da.js"></script>
<script src="/~landscape/js/bundle/index.f58fbbc4b037bb976a2a.js"></script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
</body>
</html>

View File

@ -61,8 +61,9 @@
^- json
%+ frond %chat-update
%- pairs
:~
?: ?=(%initial -.upd)
:_ ~
?- -.upd
%initial
:- %initial
%- pairs
%+ turn ~(tap by inbox.upd)
@ -73,27 +74,37 @@
:~ [%envelopes [%a (turn envelopes.mailbox envelope)]]
[%config (config config.mailbox)]
==
?: ?=(%message -.upd)
:- %message
%- pairs
:~ [%path (path path.upd)]
[%envelope (envelope envelope.upd)]
==
?: ?=(%messages -.upd)
:- %messages
%- pairs
:~ [%path (path path.upd)]
[%start (numb start.upd)]
[%end (numb end.upd)]
[%envelopes [%a (turn envelopes.upd envelope)]]
==
?: ?=(%read -.upd)
[%read (pairs [%path (path path.upd)]~)]
?: ?=(%create -.upd)
[%create (pairs [%path (path path.upd)]~)]
?: ?=(%delete -.upd)
[%delete (pairs [%path (path path.upd)]~)]
[*@t *json]
::
%message
:- %message
%- pairs
:~ [%path (path path.upd)]
[%envelope (envelope envelope.upd)]
==
::
%messages
:- %messages
%- pairs
:~ [%path (path path.upd)]
[%start (numb start.upd)]
[%end (numb end.upd)]
[%envelopes [%a (turn envelopes.upd envelope)]]
==
::
%read
[%read (pairs [%path (path path.upd)]~)]
::
%create
[%create (pairs [%path (path path.upd)]~)]
::
%delete
[%delete (pairs [%path (path path.upd)]~)]
::
%keys
:- %keys
:- %a
%+ turn ~(tap by keys.upd)
|= pax=^path (path pax)
==
--
++ dejs

View File

@ -225,7 +225,8 @@
++ add
|= [=ship =resource]
~| resource
?< (~(has by tracking) resource)
?: (~(has by tracking) resource)
[~ state]
=. tracking
(~(put by tracking) resource ship)
:_ state

14
pkg/interface/.babelrc Normal file
View File

@ -0,0 +1,14 @@
{
"plugins": [
[
"babel-plugin-root-import",
{
"paths": [
{
"rootPathSuffix": "./src"
}
]
}
]
]
}

View File

@ -2362,6 +2362,15 @@
"object.assign": "^4.1.0"
}
},
"babel-plugin-root-import": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/babel-plugin-root-import/-/babel-plugin-root-import-6.5.0.tgz",
"integrity": "sha512-PTD8fPl4v1kwn01u9d4rgRavDs5Z+jv4qa4/y6iYtoSgM4/xmjwMqo66j5A/BTZQEMA6OV5iFgyZ1PIhroJqqg==",
"dev": true,
"requires": {
"slash": "^3.0.0"
}
},
"babel-plugin-styled-components": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz",
@ -4793,6 +4802,11 @@
}
}
},
"fn-name": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/fn-name/-/fn-name-3.0.0.tgz",
"integrity": "sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA=="
},
"follow-redirects": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
@ -7441,6 +7455,11 @@
"react-is": "^16.8.1"
}
},
"property-expr": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.3.tgz",
"integrity": "sha512-TEMKBo6s4gZUKmNYwaMkS2JdDxdWgUijW/U/jLAOHVyLZfU1KHXv+mC1J9gkfGOr8532XHqMJytko1lSjc0kmw=="
},
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@ -8420,6 +8439,12 @@
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"slice-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
@ -9055,6 +9080,11 @@
"xml-reader": "2.4.3"
}
},
"synchronous-promise": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.13.tgz",
"integrity": "sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA=="
},
"tabbable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-4.0.0.tgz",
@ -9287,6 +9317,11 @@
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
"dev": true
},
"toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
},
"transformation-matrix": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.1.1.tgz",
@ -11870,6 +11905,20 @@
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
},
"yup": {
"version": "0.29.3",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.29.3.tgz",
"integrity": "sha512-RNUGiZ/sQ37CkhzKFoedkeMfJM0vNQyaz+wRZJzxdKE7VfDeVKH8bb4rr7XhRLbHJz5hSjoDNwMEIaKhuMZ8gQ==",
"requires": {
"@babel/runtime": "^7.10.5",
"fn-name": "~3.0.0",
"lodash": "^4.17.15",
"lodash-es": "^4.17.11",
"property-expr": "^2.0.2",
"synchronous-promise": "^2.0.13",
"toposort": "^2.0.2"
}
}
}
}

View File

@ -11,7 +11,7 @@
"@tlon/indigo-light": "^1.0.3",
"@tlon/indigo-react": "^1.1.15",
"classnames": "^2.2.6",
"codemirror": "^5.51.0",
"codemirror": "^5.55.0",
"css-loader": "^3.5.3",
"formik": "^2.1.4",
"lodash": "^4.17.15",
@ -32,7 +32,8 @@
"styled-system": "^5.1.5",
"suncalc": "^1.8.0",
"urbit-ob": "^5.0.0",
"urbit-sigil-js": "^1.3.2"
"urbit-sigil-js": "^1.3.2",
"yup": "^0.29.3"
},
"devDependencies": {
"@babel/core": "^7.9.0",
@ -50,6 +51,7 @@
"@typescript-eslint/parser": "^3.8.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"babel-plugin-root-import": "^6.5.0",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.2",
"eslint": "^6.8.0",

View File

@ -1,6 +1,6 @@
import _ from "lodash";
import { uuid } from "../lib/util";
import { Patp, Path } from "../types/noun";
import { Patp, Path } from "~/types/noun";
import BaseStore from '../store/base';
export default class BaseApi<S extends object = {}> {

View File

@ -1,7 +1,7 @@
import BaseApi from './base';
import { uuid } from '../lib/util';
import { Letter, ChatAction, Envelope } from '../types/chat-update';
import { Patp, Path, PatpNoSig } from '../types/noun';
import { Letter, ChatAction, Envelope } from '~/types/chat-update';
import { Patp, Path, PatpNoSig } from '~/types/noun';
import { StoreState } from '../store/type';
import BaseStore from '../store/base';

View File

@ -1,8 +1,8 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Patp, Path, Enc } from '../types/noun';
import { Contact, ContactEdit } from '../types/contact-update';
import { GroupPolicy, Resource } from '../types/group-update';
import { Patp, Path, Enc } from '~/types/noun';
import { Contact, ContactEdit } from '~/types/contact-update';
import { GroupPolicy, Resource } from '~/types/group-update';
export default class ContactsApi extends BaseApi<StoreState> {
create(

View File

@ -1,4 +1,4 @@
import { Patp } from '../types/noun';
import { Patp } from '~/types/noun';
import BaseApi from './base';
import ChatApi from './chat';
import { StoreState } from '../store/type';

View File

@ -1,13 +1,13 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Path, Patp, Enc } from '../types/noun';
import { Path, Patp, Enc } from '~/types/noun';
import {
GroupAction,
GroupPolicy,
Resource,
Tag,
GroupPolicyDiff,
} from '../types/group-update';
} from '~/types/group-update';
export default class GroupsApi extends BaseApi<StoreState> {
remove(resource: Resource, ships: Patp[]) {

View File

@ -1,6 +1,6 @@
import BaseApi from "./base";
import { StoreState } from "../store/type";
import { Serial, Path } from "../types/noun";
import { Serial, Path } from "~/types/noun";
export default class InviteApi extends BaseApi<StoreState> {
accept(app: Path, uid: Serial) {

View File

@ -2,7 +2,7 @@ import { stringToTa } from '../lib/util';
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Path } from '../types/noun';
import { Path } from '~/types/noun';
export default class LinksApi extends BaseApi<StoreState> {

View File

@ -28,7 +28,7 @@ export default class LocalApi extends BaseApi<StoreState> {
});
}
setOmnibox() {
setOmnibox() {
this.store.handleEvent({
data: {
local: {

View File

@ -1,7 +1,7 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Path, Patp } from '../types/noun';
import { Path, Patp } from '~/types/noun';
export default class MetadataApi extends BaseApi<StoreState> {

View File

@ -1,7 +1,7 @@
import BaseApi from './base';
import { PublishResponse } from '../types/publish-response';
import { PatpNoSig } from '../types/noun';
import { BookId, NoteId } from '../types/publish-update';
import { PublishResponse } from '~/types/publish-response';
import { PatpNoSig } from '~/types/noun';
import { BookId, NoteId } from '~/types/publish-update';
export default class PublishApi extends BaseApi {
handleEvent(data: PublishResponse) {

View File

@ -1,5 +1,5 @@
import { roleTags, RoleTags, Group, Resource } from '../../types/group-update';
import { PatpNoSig, Path } from '../../types/noun';
import { roleTags, RoleTags, Group, Resource } from '~/types/group-update';
import { PatpNoSig, Path } from '~/types/noun';
export function roleForShip(group: Group, ship: PatpNoSig): RoleTags | undefined {

View File

@ -1,8 +1,8 @@
import _ from 'lodash';
import { StoreState } from '../../../store/type';
import { Cage } from '../../types/cage';
import { ChatUpdate } from '../../types/chat-update';
import { ChatHookUpdate } from '../../types/chat-hook-update';
import { Cage } from '~/types/cage';
import { ChatUpdate } from '~/types/chat-update';
import { ChatHookUpdate } from '~/types/chat-hook-update';
type ChatState = Pick<StoreState, 'chatInitialized' | 'chatSynced' | 'inbox' | 'pendingMessages'>;

View File

@ -1,6 +1,6 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { Cage } from '~/types/cage';
type LocalState = Pick<StoreState, 'connection'>;

View File

@ -1,7 +1,7 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { ContactUpdate } from '../../types/contact-update';
import { Cage } from '~/types/cage';
import { ContactUpdate } from '~/types/contact-update';
type ContactState = Pick<StoreState, 'contacts'>;

View File

@ -1,6 +1,6 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { Cage } from '~/types/cage';
import {
GroupUpdate,
Group,
@ -11,8 +11,8 @@ import {
OpenPolicy,
InvitePolicyDiff,
InvitePolicy,
} from '../../types/group-update';
import { Enc, PatpNoSig } from '../../types/noun';
} from '~/types/group-update';
import { Enc, PatpNoSig } from '~/types/noun';
import { resourceAsPath } from '../lib/util';
type GroupState = Pick<StoreState, 'groups' | 'groupKeys'>;

View File

@ -1,7 +1,7 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { InviteUpdate } from '../../types/invite-update';
import { Cage } from '~/types/cage';
import { InviteUpdate } from '~/types/invite-update';
type InviteState = Pick<StoreState, "invites">;

View File

@ -1,6 +1,6 @@
import _ from 'lodash';
import { LaunchUpdate } from '../../types/launch-update';
import { Cage } from '../../types/cage';
import { LaunchUpdate } from '~/types/launch-update';
import { Cage } from '~/types/cage';
import { StoreState } from '../../store/type';
type LaunchState = Pick<StoreState, 'launch' | 'weather' | 'userLocation'>;

View File

@ -1,6 +1,6 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { LinkUpdate, Pagination } from '../../types/link-update';
import { LinkUpdate, Pagination } from '~/types/link-update';
// page size as expected from link-view.
// must change in parallel with the +page-size in /app/link-view to

View File

@ -1,7 +1,7 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { LinkListenUpdate } from '../../types/link-listen-update';
import { Cage } from '~/types/cage';
import { LinkListenUpdate } from '~/types/link-listen-update';
type LinkListenState = Pick<StoreState, 'linkListening'>;

View File

@ -1,9 +1,9 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { LocalUpdate } from '../../types/local-update';
import { Cage } from '~/types/cage';
import { LocalUpdate } from '~/types/local-update';
type LocalState = Pick<StoreState, 'sidebarShown' | 'omniboxShown' | 'dark' | 'baseHash'>;
type LocalState = Pick<StoreState, 'sidebarShown' | 'omniboxShown' | 'dark' | 'baseHash' | 'suspendedFocus'>;
export default class LocalReducer<S extends LocalState> {
reduce(json: Cage, state: S) {
@ -24,6 +24,13 @@ export default class LocalReducer<S extends LocalState> {
omniboxShown(obj: LocalUpdate, state: S) {
if ('omniboxShown' in obj) {
state.omniboxShown = !state.omniboxShown;
if (state.suspendedFocus) {
state.suspendedFocus.focus();
state.suspendedFocus = null;
} else {
state.suspendedFocus = document.activeElement;
document.activeElement?.blur();
}
}
}

View File

@ -2,8 +2,8 @@ import _ from 'lodash';
import { StoreState } from '../../store/type';
import { MetadataUpdate } from '../../types/metadata-update';
import { Cage } from '../../types/cage';
import { MetadataUpdate } from '~/types/metadata-update';
import { Cage } from '~/types/cage';
type MetadataState = Pick<StoreState, 'associations'>;

View File

@ -1,7 +1,7 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { PermissionUpdate } from '../../types/permission-update';
import { Cage } from '~/types/cage';
import { PermissionUpdate } from '~/types/permission-update';
type PermissionState = Pick<StoreState, "permissions">;

View File

@ -1,6 +1,6 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { Cage } from '~/types/cage';
type PublishState = Pick<StoreState, 'notebooks'>;

View File

@ -1,9 +1,9 @@
import _ from 'lodash';
import { PublishUpdate } from '../../types/publish-update';
import { Cage } from '../../types/cage';
import { PublishUpdate } from '~/types/publish-update';
import { Cage } from '~/types/cage';
import { StoreState } from '../../store/type';
import { getTagFromFrond } from '../../types/noun';
import { getTagFromFrond } from '~/types/noun';
type PublishState = Pick<StoreState, 'notebooks'>;

View File

@ -1,7 +1,7 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { Cage } from '../../types/cage';
import { S3Update } from '../../types/s3-update';
import { Cage } from '~/types/cage';
import { S3Update } from '~/types/s3-update';
type S3State = Pick<StoreState, 's3'>;

View File

@ -5,7 +5,7 @@ import LocalReducer from '../reducers/local';
import ChatReducer from '../reducers/chat-update';
import { StoreState } from './type';
import { Cage } from '../types/cage';
import { Cage } from '~/types/cage';
import ContactReducer from '../reducers/contact-update';
import LinkUpdateReducer from '../reducers/link-update';
import S3Reducer from '../reducers/s3-update';
@ -42,6 +42,7 @@ export default class GlobalStore extends BaseStore<StoreState> {
connection: 'connected',
sidebarShown: true,
omniboxShown: false,
suspendedFocus: null,
baseHash: null,
invites: {},
associations: {

View File

@ -1,21 +1,22 @@
import { Inbox, Envelope } from '../types/chat-update';
import { ChatHookUpdate } from '../types/chat-hook-update';
import { Path } from '../types/noun';
import { Invites } from '../types/invite-update';
import { Associations } from '../types/metadata-update';
import { Rolodex } from '../types/contact-update';
import { Notebooks } from '../types/publish-update';
import { Groups } from '../types/group-update';
import { S3State } from '../types/s3-update';
import { Permissions } from '../types/permission-update';
import { LaunchState, WeatherState } from '../types/launch-update';
import { LinkComments, LinkCollections, LinkSeen } from '../types/link-update';
import { ConnectionStatus } from '../types/connection';
import { Inbox, Envelope } from '~/types/chat-update';
import { ChatHookUpdate } from '~/types/chat-hook-update';
import { Path } from '~/types/noun';
import { Invites } from '~/types/invite-update';
import { Associations } from '~/types/metadata-update';
import { Rolodex } from '~/types/contact-update';
import { Notebooks } from '~/types/publish-update';
import { Groups } from '~/types/group-update';
import { S3State } from '~/types/s3-update';
import { Permissions } from '~/types/permission-update';
import { LaunchState, WeatherState } from '~/types/launch-update';
import { LinkComments, LinkCollections, LinkSeen } from '~/types/link-update';
import { ConnectionStatus } from '~/types/connection';
export interface StoreState {
// local state
sidebarShown: boolean;
omniboxShown: boolean;
suspendedFocus: HTMLInputElement | null;
dark: boolean;
connection: ConnectionStatus;
baseHash: string | null;

View File

@ -1,6 +1,6 @@
import BaseStore from "../store/base";
import BaseApi from "../api/base";
import { Path } from "../types/noun";
import { Path } from "~/types/noun";
export default class BaseSubscription<S extends object> {
private errorCount = 0;

View File

@ -1,6 +1,6 @@
import BaseSubscription from './base';
import { StoreState } from '../store/type';
import { Path } from '../types/noun';
import { Path } from '~/types/noun';
import _ from 'lodash';

View File

@ -18,11 +18,11 @@ import StatusBar from './components/StatusBar';
import Omnibox from './components/Omnibox';
import ErrorComponent from './components/Error';
import GlobalStore from '../logic/store/store';
import GlobalSubscription from '../logic/subscription/global';
import GlobalApi from '../logic/api/global';
import { uxToHex } from '../logic/lib/util';
import { Sigil } from '../logic/lib/sigil';
import GlobalStore from '~/logic/store/store';
import GlobalSubscription from '~/logic/subscription/global';
import GlobalApi from '~/logic/api/global';
import { uxToHex } from '~/logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
const Root = styled.div`
font-family: ${p => p.theme.fonts.sans};
@ -30,6 +30,8 @@ const Root = styled.div`
width: 100%;
padding: 0;
margin: 0;
display: flex;
flex-flow: column nowrap;
`;
const StatusBarWithRouter = withRouter(StatusBar);
@ -59,6 +61,7 @@ class App extends React.Component {
this.api.local.getBaseHash();
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
e.preventDefault();
e.stopImmediatePropagation();
this.api.local.setOmnibox();
});
this.setFavicon();

View File

@ -11,11 +11,11 @@ import { SettingsScreen } from './components/settings';
import { NewScreen } from './components/new';
import { JoinScreen } from './components/join';
import { NewDmScreen } from './components/new-dm';
import { PatpNoSig } from '../../../types/noun';
import GlobalApi from '../../logic/api/global';
import { StoreState } from '../../logic/store/type';
import GlobalSubscription from '../../logic/subscription/global';
import {groupBunts} from '../../../types/group-update';
import { PatpNoSig } from '~/types/noun';
import GlobalApi from '~/logic/api/global';
import { StoreState } from '~/logic/store/type';
import GlobalSubscription from '~/logic/subscription/global';
import {groupBunts} from '~/types/group-update';
type ChatAppProps = StoreState & {
ship: PatpNoSig;

View File

@ -6,15 +6,15 @@ import { Link, RouteComponentProps } from "react-router-dom";
import { ChatWindow } from './lib/chat-window';
import { ChatHeader } from './lib/chat-header';
import { ChatInput } from "./lib/chat-input";
import { deSig } from "../../../../logic/lib/util";
import { ChatHookUpdate } from "../../../../types/chat-hook-update";
import ChatApi from "../../../../logic/api/chat";
import { Inbox, Envelope } from "../../../../types/chat-update";
import { Contacts } from "../../../../types/contact-update";
import { Path, Patp } from "../../../../types/noun";
import GlobalApi from "../../../../logic/api/global";
import { Association } from "../../../../types/metadata-update";
import {Group} from "../../../../types/group-update";
import { deSig } from "~/logic/lib/util";
import { ChatHookUpdate } from "~/types/chat-hook-update";
import ChatApi from "~/logic/api/chat";
import { Inbox, Envelope } from "~/types/chat-update";
import { Contacts } from "~/types/contact-update";
import { Path, Patp } from "~/types/noun";
import GlobalApi from "~/logic/api/global";
import { Association } from "~/types/metadata-update";
import {Group} from "~/types/group-update";
type ChatScreenProps = RouteComponentProps<{

View File

@ -2,145 +2,99 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Spinner } from '../../../components/Spinner';
import urbitOb from 'urbit-ob';
import { Box, Text, Input, Button } from '@tlon/indigo-react';
import { Formik, Form } from 'formik'
import * as Yup from 'yup';
const schema = Yup.object().shape({
station: Yup.string()
.lowercase()
.trim()
.test('is-station',
'Chat must have a valid name',
(val) =>
val &&
val.split('/').length === 2 &&
urbitOb.isValidPatp(val.split('/')[0])
)
.required('Required')
});
export class JoinScreen extends Component {
constructor(props) {
super(props);
this.state = {
station: '/',
error: false,
awaiting: false
};
this.stationChange = this.stationChange.bind(this);
}
componentDidMount() {
this.componentDidUpdate();
if (this.props.station) {
this.onSubmit({ station: this.props.station });
}
}
componentDidUpdate(prevProps, prevState) {
const { props, state } = this;
if ((props.autoJoin !== '/undefined/undefined') &&
(props.api && (prevProps?.api !== props.api))) {
let station = props.autoJoin.split('/');
const ship = station[1];
if (
station.length < 2 ||
!urbitOb.isValidPatp(ship)
) {
this.setState({
error: true
});
onSubmit(values) {
console.log(values);
this.setState({ awaiting: true }, () => {
console.log(values);
const station = values.station.trim();
if (`/${station}` in this.props.chatSynced) {
this.props.history.push(`/~chat/room/${station}`);
return;
}
station = props.autoJoin;
this.setState({
station,
awaiting: true
}, () => props.api.chat.join(ship, station, true));
}
if (state.station in props.inbox ||
(props?.chatSynced !== prevProps?.chatSynced && state.station !== '/')) {
this.setState({ awaiting: false });
props.history.push(`/~chat/room${state.station}`);
}
}
onClickJoin() {
const { props, state } = this;
let station = state.station.split('/');
const ship = station[1];
if (
station.length < 2 ||
!urbitOb.isValidPatp(ship)
) {
this.setState({
error: true
});
return;
}
station = state.station.trim();
this.setState({
station,
awaiting: true
}, () => {
props.api.chat.join(ship, station, true);
});
}
stationChange(event) {
this.setState({
station: `/${event.target.value.trim()}`
props.api.chat.join(ship, station, true)
this.props.history.push(`/~chat/room/${station}`);
});
}
render() {
const { state } = this;
let joinClasses = 'db f9 green2 ba pa2 b--green2 bg-gray0-d pointer';
if ((!state.station) || (state.station === '/')) {
joinClasses = 'db f9 gray2 ba pa2 b--gray3 bg-gray0-d pointer';
}
let errElem = (<span />);
if (state.error) {
errElem = (
<span className="f9 inter red2 db">
Chat must have a valid name.
</span>
);
}
const { props, state } = this;
return (
<div className={`h-100 w-100 pa3 pt2 overflow-x-hidden flex flex-column
bg-gray0-d white-d`}
>
<div
className="w-100 dn-m dn-l dn-xl inter pt1 pb6 f8"
>
<Link to="/~chat/">{'⟵ All Chats'}</Link>
</div>
<h2 className="mb3 f8">Join Existing Chat</h2>
<div className="w-100">
<p className="f8 lh-copy mt3 db">Enter a <span className="mono">~ship/chat-name</span></p>
<p className="f9 gray2 mb4">Chat names use lowercase, hyphens, and slashes.</p>
<textarea
ref={ (e) => {
this.textarea = e;
} }
className={'f7 mono ba bg-gray0-d white-d pa3 mb2 db ' +
'focus-b--black focus-b--white-d b--gray3 b--gray2-d'}
placeholder="~zod/chatroom"
spellCheck="false"
rows={1}
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.onClickJoin();
}
}}
style={{
resize: 'none'
}}
onChange={this.stationChange}
/>
{errElem}
<br />
<button
onClick={this.onClickJoin.bind(this)}
className={joinClasses}
>Join Chat</button>
<Spinner awaiting={this.state.awaiting} classes="mt4" text="Joining chat..." />
</div>
</div>
<Formik
enableReinitialize={true}
initialValues={{ station: props.station }}
validationSchema={schema}
onSubmit={this.onSubmit.bind(this)}>
<Form>
<Box width="100%" height="100%" p={3} overflowX="hidden">
<Box
width="100%"
pt={1} pb={5}
display={['', 'none', 'none', 'none']}
fontSize={0}>
<Link to="/~chat/">{'⟵ All Chats'}</Link>
</Box>
<Text mb={3} fontSize={0}>Join Existing Chat</Text>
<Box width="100%" maxWidth={350}>
<Box mt={3} mb={3} display="block">
<Text display="inline" fontSize={0}>
Enter a{' '}
</Text>
<Text display="inline" fontSize={0} fontFamily="mono">
~ship/chat-name
</Text>
</Box>
<Input
mt={4}
id="station"
placeholder="~zod/chatroom"
fontFamily="mono"
caption="Chat names use lowercase, hyphens, and slashes." />
<Button>Join Chat</Button>
<Spinner
awaiting={this.state.awaiting}
classes="mt4"
text="Joining chat..." />
</Box>
</Box>
</Form>
</Formik>
);
}
}

View File

@ -15,7 +15,7 @@ const MARKDOWN_CONFIG = {
name: 'markdown',
tokenTypeOverrides: {
header: 'presentation',
quote: 'presentation',
quote: 'quote',
list1: 'presentation',
list2: 'presentation',
list3: 'presentation',
@ -121,16 +121,18 @@ export default class ChatEditor extends Component {
return (
<div
className="chat fr h-100 flex bg-gray0-d lh-copy pl2 w-100 items-center"
style={{ flexGrow: 1, maxHeight: '224px', width: 'calc(100% - 72px)' }}
>
className={
'chat fr h-100 flex bg-gray0-d lh-copy pl2 w-100 items-center' +
(props.inCodeMode ? ' code' : '')
}
style={{ flexGrow: 1, maxHeight: '224px', width: 'calc(100% - 72px)' }}>
<CodeEditor
value={props.message}
options={options}
onChange={(e, d, v) => this.messageChange(e, d, v)}
editorDidMount={(editor) => {
this.editor = editor;
if (!(BROWSER_REGEX.test(navigator.userAgent))) {
if (!BROWSER_REGEX.test(navigator.userAgent)) {
editor.focus();
}
}}

View File

@ -2,8 +2,8 @@ import React, { Component, Fragment } from "react";
import { Link } from "react-router-dom";
import { ChatTabBar } from "./chat-tabbar";
import { SidebarSwitcher } from "../../../../components/SidebarSwitch";
import { deSig } from "../../../../../logic/lib/util";
import { SidebarSwitcher } from "~/views/components/SidebarSwitch";
import { deSig } from "~/logic/lib/util";
export const ChatHeader = (props) => {

View File

@ -2,8 +2,8 @@ import React, { Component } from 'react';
import ChatEditor from './chat-editor';
import { S3Upload } from './s3-upload'
;
import { uxToHex } from '../../../../../logic/lib/util';
import { Sigil } from '../../../../../logic/lib/sigil';
import { uxToHex } from '~/logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
const URL_REGEX = new RegExp(String(/^((\w+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+)/.source));

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from "react";
import { scrollIsAtTop, scrollIsAtBottom } from "../../../../../logic/lib/util";
import { scrollIsAtTop, scrollIsAtBottom } from "~/logic/lib/util";
// Restore chat position on FF when new messages come in
const recalculateScrollTop = (lastScrollHeight, scrollContainer) => {

View File

@ -11,14 +11,14 @@ export default class CodeContent extends Component {
(Boolean(content.code.output) &&
content.code.output.length && content.code.output.length > 0) ?
(
<pre className={`f7 clamp-attachment pa1 mt0 mb0 b--gray4 b--gray1-d bl br bb`}>
<pre className={`code f7 clamp-attachment pa1 mt0 mb0`}>
{content.code.output[0].join('\n')}
</pre>
) : null;
return (
<div className="mv2">
<pre className={`f7 clamp-attachment pa1 mt0 mb0 bg-light-gray b--gray4 b--gray1-d ba`}>
<pre className={`code f7 clamp-attachment pa1 mt0 mb0`}>
{content.code.expression}
</pre>
{outputElement}

View File

@ -6,7 +6,6 @@ import urbitOb from 'urbit-ob';
const DISABLED_BLOCK_TOKENS = [
'indentedCode',
'blockquote',
'atxHeading',
'thematicBreak',
'list',
@ -41,7 +40,7 @@ export default class TextContent extends Component {
const content = props.content;
const group = content.text.match(
/([~][/])?(~[a-z]{3,6})(-[a-z]{6})?([/])(([a-z])+([/-])?)+/
/([~][/])?(~[a-z]{3,6})(-[a-z]{6})?([/])(([a-z0-9-])+([/-])?)+/
);
if ((group !== null) // matched possible chatroom
&& (group[2].length > 2) // possible ship?

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react';
import { Button } from '@tlon/indigo-react';
const IMAGE_REGEX = new RegExp(/(jpg|img|png|gif|tiff|jpeg|webp|webm|svg)$/i);
@ -79,11 +80,14 @@ export default class UrlContent extends Component {
>
{content.url}
</a>
<a className="bs ml2 f7 pointer lh-copy v-top"
onClick={e => this.unfoldEmbed()}
<Button
border={1}
style={{ display: 'inline-flex', height: '1.66em' }} // Height is hacked to line-height until Button supports proper size
ml={1}
onClick={e => this.unfoldEmbed()}
>
[embed]
</a>
{this.state.unfold ? 'collapse' : 'embed'}
</Button>
{contents}
</div>
);

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import Toggle from '../../../../components/toggle';
import { InviteSearch } from '../../../../components/InviteSearch';
import Toggle from '~/views/components/toggle';
import { InviteSearch } from '~/views/components/InviteSearch';
export class GroupifyButton extends Component {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { InviteSearch } from '../../../../components/InviteSearch';
import { Spinner } from '../../../../components/Spinner';
import { InviteSearch } from '~/views/components/InviteSearch';
import { Spinner } from '~/views/components/Spinner';
export class InviteElement extends Component {
constructor(props) {

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { OverlaySigil } from './overlay-sigil';
import MessageContent from './message-content';
import { uxToHex, cite, writeText } from '../../../../../logic/lib/util';
import { uxToHex, cite, writeText } from '~/logic/lib/util';
import moment from 'moment';

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { uxToHex } from '../../../../../logic/lib/util';
import { uxToHex } from '~/logic/lib/util';
export class MetadataColor extends Component {

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { MetadataColor } from './metadata-color';
import { MetadataInput } from './metadata-input';
import { uxToHex } from '../../../../../logic/lib/util';
import { uxToHex } from '~/logic/lib/util';
export const MetadataSettings = (props) => {

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { Sigil } from '../../../../../logic/lib/sigil';
import { Sigil } from '~/logic/lib/sigil';
import {
ProfileOverlay,
OVERLAY_HEIGHT

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { cite } from '../../../../../logic/lib/util';
import { Sigil } from '../../../../../logic/lib/sigil';
import { cite } from '~/logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
export const OVERLAY_HEIGHT = 250;

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import S3Client from '../../../../../logic/lib/s3';
import S3Client from '~/logic/lib/s3';
export class S3Upload extends Component {
constructor(props) {

View File

@ -1,9 +1,9 @@
import React, { Component } from 'react';
import { Spinner } from '../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
import { Link } from 'react-router-dom';
import { InviteSearch } from '../../../components/InviteSearch';
import { InviteSearch } from '~/views/components/InviteSearch';
import urbitOb from 'urbit-ob';
import { deSig } from '../../../../logic/lib/util';
import { deSig } from '~/logic/lib/util';
export class NewDmScreen extends Component {
constructor(props) {

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react';
import { InviteSearch } from '../../../components/InviteSearch';
import { Spinner } from '../../../components/Spinner';
import { InviteSearch } from '~/views/components/InviteSearch';
import { Spinner } from '~/views/components/Spinner';
import { Link } from 'react-router-dom';
import { deSig } from '../../../../logic/lib/util';
import { deSig } from '~/logic/lib/util';
export class NewScreen extends Component {
constructor(props) {

View File

@ -1,14 +1,14 @@
import React, { Component, Fragment } from 'react';
import { deSig } from '../../../../logic/lib/util';
import { deSig } from '~/logic/lib/util';
import { Link } from 'react-router-dom';
import { ChatHeader } from './lib/chat-header';
import { MetadataSettings } from './lib/metadata-settings';
import { DeleteButton } from './lib/delete-button';
import { GroupifyButton } from './lib/groupify-button';
import { Spinner } from '../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
import { ChatTabBar } from './lib/chat-tabbar';
import SidebarSwitcher from '../../../components/SidebarSwitch';
import SidebarSwitcher from '~/views/components/SidebarSwitch';
export class SettingsScreen extends Component {

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react';
import Welcome from './lib/welcome';
import { alphabetiseAssociations } from '../../../../logic/lib/util';
import SidebarInvite from '../../../components/SidebarInvite';
import { alphabetiseAssociations } from '~/logic/lib/util';
import SidebarInvite from '~/views/components/SidebarInvite';
import { GroupItem } from './lib/group-item';
export class Sidebar extends Component {

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import ErrorBoundary from '../../../components/ErrorBoundary';
import ErrorBoundary from '~/views/components/ErrorBoundary';
export class Skeleton extends Component {
render() {

View File

@ -256,9 +256,16 @@ blockquote {
font-family: 'Inter';
}
.chat .CodeMirror.cm-s-code.chat .cm-s-tlon * {
font-family: 'Source Code Pro';
code, pre.code {
background-color: var(--light-gray);
}
code, .code, .chat.code .react-codemirror2 .CodeMirror * {
font-family: 'Source Code Pro';
}
.chat .CodeMirror.cm-s-code.chat * {
font-family: 'Source Code Pro';
}
.chat .CodeMirror-selected { background:#BAE3FE !important; color: black; }
@ -267,6 +274,7 @@ pre.CodeMirror-placeholder.CodeMirror-line-like { color: var(--gray); }
.chat .cm-s-tlon span { font-family: "Inter"}
.chat .cm-s-tlon span.cm-meta { color: var(--gray); }
.chat .cm-s-tlon span.cm-number { color: var(--gray); }
.chat .cm-s-tlon span.cm-quote { color: var(--gray); }
.chat .cm-s-tlon span.cm-keyword { line-height: 1em; font-weight: bold; color: var(--gray); }
.chat .cm-s-tlon span.cm-atom { font-weight: bold; color: var(--gray); }
.chat .cm-s-tlon span.cm-def { color: black; }

View File

@ -48,7 +48,7 @@ export default class DojoApp extends Component {
return (
<div
className="bg-white bg-gray0-d"
style={{ height: 'calc(100vh - 45px)' }}
style={{ height: '100%' }}
>
<Route
exact

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { cite } from '../../../../logic/lib/util';
import { Spinner } from '../../../components/Spinner';
import { cite } from '~/logic/lib/util';
import { Spinner } from '~/views/components/Spinner';
export class Input extends Component {
constructor(props) {
@ -14,10 +14,16 @@ export class Input extends Component {
}
componentDidUpdate() {
if (
!document.activeElement == document.body
|| document.activeElement == this.inputRef.current
) {
this.inputRef.current.focus();
this.inputRef.current.setSelectionRange(this.props.cursor, this.props.cursor);
}
}
keyPress = (e) => {
keyPress(e) {
if ((e.getModifierState('Control') || event.getModifierState('Meta'))
&& e.key === 'v') {
return;
@ -33,75 +39,79 @@ export class Input extends Component {
return;
}
// submit on enter
if (e.key === 'Enter') {
this.setState({ awaiting: true, type: 'Sending to Dojo' });
this.props.api.soto('ret').then(() => {
this.setState({ awaiting: false });
});
} else if ((e.key === 'Backspace') && (this.props.cursor > 0)) {
this.props.store.doEdit({ del: this.props.cursor - 1 });
return this.props.store.setState({ cursor: this.props.cursor - 1 });
} else if (e.key === 'Backspace') {
return;
} else if (e.key.startsWith('Arrow')) {
if (e.key === 'ArrowLeft') {
if (this.props.cursor > 0) {
this.props.store.setState({ cursor: this.props.cursor - 1 });
}
} else if (e.key === 'ArrowRight') {
if (this.props.cursor < this.props.input.length) {
this.props.store.setState({ cursor: this.props.cursor + 1 });
// submit on enter
if (e.key === 'Enter') {
this.setState({ awaiting: true, type: 'Sending to Dojo' });
this.props.api.soto('ret').then(() => {
this.setState({ awaiting: false });
});
} else if ((e.key === 'Backspace') && (this.props.cursor > 0)) {
this.props.store.doEdit({ del: this.props.cursor - 1 });
return this.props.store.setState({ cursor: this.props.cursor - 1 });
} else if (e.key === 'Backspace') {
return;
} else if (e.key.startsWith('Arrow')) {
if (e.key === 'ArrowLeft') {
if (this.props.cursor > 0) {
this.props.store.setState({ cursor: this.props.cursor - 1 });
}
} else if (e.key === 'ArrowRight') {
if (this.props.cursor < this.props.input.length) {
this.props.store.setState({ cursor: this.props.cursor + 1 });
}
}
}
// tab completion
else if (e.key === 'Tab') {
this.setState({ awaiting: true, type: 'Getting suggestions' });
this.props.api.soto({ tab: this.props.cursor }).then(() => {
this.setState({ awaiting: false });
});
}
// capture and transmit most characters
else {
this.props.store.doEdit({ ins: { cha: e.key, at: this.props.cursor } });
this.props.store.setState({ cursor: this.props.cursor + 1 });
}
}
// tab completion
else if (e.key === 'Tab') {
this.setState({ awaiting: true, type: 'Getting suggestions' });
this.props.api.soto({ tab: this.props.cursor }).then(() => {
this.setState({ awaiting: false });
});
}
// capture and transmit most characters
else {
this.props.store.doEdit({ ins: { cha: e.key, at: this.props.cursor } });
this.props.store.setState({ cursor: this.props.cursor + 1 });
}
}
render() {
return (
<div className="flex flex-row flex-grow-1 relative">
<div className="flex-shrink-0">{cite(this.props.ship)}:dojo
render() {
return (
<div className="flex flex-row flex-grow-1 relative">
<div className="flex-shrink-0"><span class="dn-s">{cite(this.props.ship)}:</span>dojo
</div>
<span id="prompt">
{this.props.prompt}
</span>
<input
autoFocus
autocorrect="off"
autocapitalize="off"
spellcheck="false"
tabindex="0"
wrap="off"
className="mono ml1 flex-auto dib w-100"
id="dojo"
cursor={this.props.cursor}
onClick={e => this.props.store.setState({ cursor: e.target.selectionEnd })}
onKeyDown={this.keyPress}
onPaste={(e) => {
const clipboardData = e.clipboardData || window.clipboardData;
const paste = Array.from(clipboardData.getData('Text'));
paste.reduce(async (previous, next) => {
await previous;
this.setState({ cursor: this.props.cursor + 1 });
return this.props.store.doEdit({ ins: { cha: next, at: this.props.cursor } });
}, Promise.resolve());
e.preventDefault();
}}
ref={this.inputRef}
defaultValue={this.props.input}
/>
<Spinner awaiting={this.state.awaiting} text={`${this.state.type}...`} classes="absolute right-0 bottom-0 inter pa ba pa2 b--gray1-d" />
</div>
<span id="prompt">
{this.props.prompt}
</span>
<input
autoCorrect="false"
autoFocus={true}
className="mono ml1 flex-auto dib w-100"
id="dojo"
cursor={this.props.cursor}
onClick={e => this.props.store.setState({ cursor: e.target.selectionEnd })}
onKeyDown={this.keyPress}
onPaste={(e) => {
const clipboardData = e.clipboardData || window.clipboardData;
const paste = Array.from(clipboardData.getData('Text'));
paste.reduce(async (previous, next) => {
await previous;
this.setState({ cursor: this.props.cursor + 1 });
return this.props.store.doEdit({ ins: { cha: next, at: this.props.cursor } });
}, Promise.resolve());
e.preventDefault();
}}
ref={this.inputRef}
defaultValue={this.props.input}
/>
<Spinner awaiting={this.state.awaiting} text={`${this.state.type}...`} classes="absolute right-0 bottom-0 inter pa ba pa2 b--gray1-d" />
</div>
);
}
}

View File

@ -11,10 +11,10 @@ import { AddScreen } from './components/lib/add-contact';
import { JoinScreen } from './components/join';
import GroupDetail from './components/lib/group-detail';
import { PatpNoSig } from '../../../types/noun';
import GlobalApi from '../../../logic/api/global';
import { StoreState } from '../../../logic/store/type';
import GlobalSubscription from '../../../logic/subscription/global';
import { PatpNoSig } from '~/types/noun';
import GlobalApi from '~/logic/api/global';
import { StoreState } from '~/logic/store/type';
import GlobalSubscription from '~/logic/subscription/global';
type GroupsAppProps = StoreState & {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Spinner } from '../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
import urbitOb from 'urbit-ob';
export class JoinScreen extends Component {

View File

@ -1,12 +1,12 @@
import React, { Component } from 'react';
import _ from 'lodash';
import { Link } from 'react-router-dom';
import { InviteSearch, Invites } from '../../../../components/InviteSearch';
import { Spinner } from '../../../../components/Spinner';
import { InviteSearch, Invites } from '~/views/components/InviteSearch';
import { Spinner } from '~/views/components/Spinner';
import { uuid } from '../../../../lib/util';
import { Groups } from '../../../../types/group-update';
import { Rolodex } from '../../../../types/contact-update';
import { Path } from '../../../../types/noun';
import { Groups } from '~/types/group-update';
import { Rolodex } from '~/types/contact-update';
import { Path } from '~/types/noun';
import GlobalApi from '../../../../api/global';
import { History } from 'history';

View File

@ -1,10 +1,10 @@
import React, { Component } from 'react';
import { Sigil } from '../../../../../logic/lib/sigil';
import { Sigil } from '~/logic/lib/sigil';
import { Link } from 'react-router-dom';
import { EditElement } from './edit-element';
import { Spinner } from '../../../../components/Spinner';
import { uxToHex } from '../../../../../logic/lib/util';
import { Spinner } from '~/views/components/Spinner';
import { uxToHex } from '~/logic/lib/util';
import { S3Upload } from './s3-upload';
export class ContactCard extends Component {

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Sigil } from '../../../../../logic/lib/sigil';
import { uxToHex, cite } from '../../../../../logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
import { uxToHex, cite } from '~/logic/lib/util';
export class ContactItem extends Component {
render() {

View File

@ -4,14 +4,14 @@ import { FixedSizeList as List } from 'react-window';
import { ContactItem } from './contact-item';
import { ShareSheet } from './share-sheet';
import { Sigil } from '../../../../../logic/lib/sigil';
import { Spinner } from '../../../../components/Spinner';
import { cite } from '../../../../../logic/lib/util';
import { roleForShip, resourceFromPath } from '../../../../../logic/lib/group';
import { Path, PatpNoSig } from '../../../../../types/noun';
import { Rolodex, Contacts, Contact } from '../../../../../types/contact-update';
import { Groups, Group } from '../../../../../types/group-update';
import GlobalApi from '../../../../../logic/api/global';
import { Sigil } from '~/logic/lib/sigil';
import { Spinner } from '~/views/components/Spinner';
import { cite } from '~/logic/lib/util';
import { roleForShip, resourceFromPath } from '~/logic/lib/group';
import { Path, PatpNoSig } from '~/types/noun';
import { Rolodex, Contacts, Contact } from '~/types/contact-update';
import { Groups, Group } from '~/types/group-update';
import GlobalApi from '~/logic/api/global';
interface ContactSidebarProps {
activeDrawer: 'contacts' | 'detail' | 'rightPanel';

View File

@ -1,11 +1,11 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Spinner } from '../../../../components/Spinner';
import { Toggle } from '../../../../components/toggle';
import { GroupView } from '../../../../components/Group';
import { Spinner } from '~/views/components/Spinner';
import { Toggle } from '~/views/components/toggle';
import { GroupView } from '~/views/components/Group';
import { deSig, uxToHex, writeText } from '../../../../../logic/lib/util';
import { roleForShip, resourceFromPath } from '../../../../../logic/lib/group';
import { deSig, uxToHex, writeText } from '~/logic/lib/util';
import { roleForShip, resourceFromPath } from '~/logic/lib/group';
export class GroupDetail extends Component {
constructor(props) {
@ -19,6 +19,7 @@ export class GroupDetail extends Component {
this.changeTitle = this.changeTitle.bind(this);
this.changeDescription = this.changeDescription.bind(this);
this.changePolicy = this.changePolicy.bind(this);
this.getShortcode = this.getShortcode.bind(this);
}
componentDidMount() {
@ -185,6 +186,41 @@ export class GroupDetail extends Component {
);
}
getShortcode(group, path) {
if (group?.policy?.open) {
return (
<div className='mt4'>
<p className='f9 mt4 lh-copy'>Share</p>
<p className='f9 gray2 mb2'>
Share a shortcode to join this group
</p>
<div
className='relative w-100 flex'
style={{ maxWidth: '29rem' }}>
<input
className={'f8 mono ba b--gray3 b--gray2-d bg-gray0-d ' +
'white-d pa3 db w-100 flex-auto mr3 pr9'}
disabled={true}
value={path.substr(6)}
/>
<span
className='lh-solid f8 pointer absolute pa3 inter'
style={{ right: 12, top: 1 }}
ref='copy'
onClick={() => {
writeText(path.substr(6));
this.refs.copy.innerText = 'Copied';
}}>
Copy
</span>
</div>
</div>
);
} else {
return <div />;
};
}
renderSettings() {
const { props } = this;
@ -201,33 +237,8 @@ export class GroupDetail extends Component {
{ description: 'Janitor', tag: 'janitor', addDescription: 'Make Janitor' }
];
let shortcode = <div />;
const shortcode = this.getShortcode(group, props.path);
if (group?.policy?.open) {
shortcode = <div className="mt4">
<p className="f9 mt4 lh-copy">Share</p>
<p className="f9 gray2 mb2">Share a shortcode to join this group</p>
<div className="relative w-100 flex"
style={{ maxWidth: '29rem' }}
>
<input
className="f8 mono ba b--gray3 b--gray2-d bg-gray0-d white-d pa3 db w-100 flex-auto mr3"
disabled={true}
value={props.path.substr(6)}
/>
<span className="lh-solid f8 pointer absolute pa3 inter"
style={{ right: 12, top: 1 }}
ref="copy"
onClick={() => {
writeText(props.path.substr(6));
this.refs.copy.innerText = 'Copied';
}}
>
Copy
</span>
</div>
</div>;
}
return (
<div className="pa4 w-100 h-100 white-d overflow-y-auto">
<div className="f8 f9-m f9-l f9-xl w-100">

View File

@ -2,11 +2,11 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { GroupItem } from './group-item';
import SidebarInvite from '../../../../components/SidebarInvite';
import SidebarInvite from '~/views/components/SidebarInvite';
import { Welcome } from './welcome';
import { cite } from '../../../../../logic/lib/util';
import { Sigil } from '../../../../../logic/lib/sigil';
import { cite } from '~/logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
export class GroupSidebar extends Component {

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'
import S3Client from '../../../../../logic/lib/s3';
import S3Client from '~/logic/lib/s3';
export class S3Upload extends Component {

View File

@ -1,15 +1,15 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { InviteSearch, Invites } from '../../../components/InviteSearch';
import { Spinner } from '../../../components/Spinner';
import { Toggle } from '../../../components/toggle';
import { InviteSearch, Invites } from '~/views/components/InviteSearch';
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 GlobalApi from '../../../../logic/api/global';
import { Patp, PatpNoSig, Enc } from '../../../../types/noun';
import { Groups, GroupPolicy, Resource } from '~/types/group-update';
import { Contacts, Rolodex } from '~/types/contact-update';
import GlobalApi from '~/logic/api/global';
import { Patp, PatpNoSig, Enc } from '~/types/noun';
type NewScreenProps = Pick<RouteComponentProps, 'history'> & {
groups: Groups;

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { GroupSidebar } from './lib/group-sidebar';
import ErrorBoundary from '../../../components/ErrorBoundary';
import ErrorBoundary from '~/views/components/ErrorBoundary';
export class Skeleton extends Component {
render() {

View File

@ -1,7 +1,7 @@
import React from 'react';
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import defaultApps from '../../../../../logic/lib/default-apps';
import defaultApps from '~/logic/lib/default-apps';
import Tile from './tile';

View File

@ -15,7 +15,7 @@ import {
makeRoutePath,
amOwnerOfGroup,
base64urlDecode
} from '../../../logic/lib/util';
} from '~/logic/lib/util';
export class LinksApp extends Component {
constructor(props) {

View File

@ -2,9 +2,9 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { GroupItem } from './group-item';
import SidebarInvite from '../../../../components/SidebarInvite';
import SidebarInvite from '~/views/components/SidebarInvite';
import { Welcome } from './welcome';
import { alphabetiseAssociations } from '../../../../../logic/lib/util';
import { alphabetiseAssociations } from '~/logic/lib/util';
export class ChannelsSidebar extends Component {
// drawer to the left

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { makeRoutePath } from '../../../../../logic/lib/util';
import { makeRoutePath } from '~/logic/lib/util';
export class ChannelsItem extends Component {
render() {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Sigil } from '../../../../../logic/lib/sigil';
import { cite } from '../../../../../logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
import { cite } from '~/logic/lib/util';
import moment from 'moment';
import { Box, Text, Row } from '@tlon/indigo-react';

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { makeRoutePath } from '../../../../../logic/lib/util';
import { makeRoutePath } from '~/logic/lib/util';
export class CommentsPagination extends Component {
render() {

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { CommentItem } from './comment-item';
import { CommentsPagination } from './comments-pagination';
import { getContactDetails } from '../../../../../logic/lib/util';
import { getContactDetails } from '~/logic/lib/util';
export class Comments extends Component {
constructor(props) {
super(props);

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { cite } from '../../../../../logic/lib/util';
import { cite } from '~/logic/lib/util';
import moment from 'moment';
export class LinkPreview extends Component {

View File

@ -1,9 +1,9 @@
import React, { Component } from 'react';
import moment from 'moment';
import { Sigil } from '../../../../../logic/lib/sigil';
import { Sigil } from '~/logic/lib/sigil';
import { Link } from 'react-router-dom';
import { makeRoutePath, cite } from '../../../../../logic/lib/util';
import { makeRoutePath, cite } from '~/logic/lib/util';
export class LinkItem extends Component {
constructor(props) {

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { Spinner } from '../../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
export class LinkSubmit extends Component {
constructor() {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { makeRoutePath } from '../../../../../logic/lib/util';
import { makeRoutePath } from '~/logic/lib/util';
export class LinksTabBar extends Component {
render() {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Sigil } from '../../../../../logic/lib/sigil';
import { uxToHex, cite } from '../../../../../logic/lib/util';
import { Sigil } from '~/logic/lib/sigil';
import { uxToHex, cite } from '~/logic/lib/util';
export class MemberElement extends Component {
onRemove() {
const { props } = this;

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { makeRoutePath } from '../../../../../logic/lib/util';
import { makeRoutePath } from '~/logic/lib/util';
export class Pagination extends Component {
render() {

View File

@ -1,12 +1,12 @@
import React, { Component } from 'react';
import { LinksTabBar } from './lib/links-tabbar';
import { LinkPreview } from './lib/link-detail-preview';
import { SidebarSwitcher } from '../../../components/SidebarSwitch';
import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
import { Link } from 'react-router-dom';
import { Comments } from './lib/comments';
import { Spinner } from '../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
import { LoadingScreen } from './loading';
import { makeRoutePath, getContactDetails } from '../../../../logic/lib/util';
import { makeRoutePath, getContactDetails } from '~/logic/lib/util';
import CommentItem from './lib/comment-item';
export class LinkDetail extends Component {

View File

@ -3,13 +3,13 @@ import React, { Component } from 'react';
import { LoadingScreen } from './loading';
import { MessageScreen } from './lib/message-screen';
import { LinksTabBar } from './lib/links-tabbar';
import { SidebarSwitcher } from '../../../components/SidebarSwitch';
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 { Pagination } from './lib/pagination';
import { makeRoutePath, getContactDetails } from '../../../../logic/lib/util';
import { makeRoutePath, getContactDetails } from '~/logic/lib/util';
export class Links extends Component {
constructor(props) {

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react';
import { InviteSearch } from '../../../components/InviteSearch';
import { Spinner } from '../../../components/Spinner';
import { InviteSearch } from '~/views/components/InviteSearch';
import { Spinner } from '~/views/components/Spinner';
import { Link } from 'react-router-dom';
import { makeRoutePath, deSig } from '../../../../logic/lib/util';
import { makeRoutePath, deSig } from '~/logic/lib/util';
import urbitOb from 'urbit-ob';
export class NewScreen extends Component {

View File

@ -1,12 +1,12 @@
import React, { Component } from 'react';
import { uxToHex, makeRoutePath } from '../../../../logic/lib/util';
import { uxToHex, makeRoutePath } from '~/logic/lib/util';
import { Link } from 'react-router-dom';
import { LoadingScreen } from './loading';
import { Spinner } from '../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
import { LinksTabBar } from './lib/links-tabbar';
import SidebarSwitcher from '../../../components/SidebarSwitch';
import SidebarSwitcher from '~/views/components/SidebarSwitch';
export class SettingsScreen extends Component {
constructor(props) {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { ChannelsSidebar } from './lib/channel-sidebar';
import ErrorBoundary from '../../../components/ErrorBoundary';
import ErrorBoundary from '~/views/components/ErrorBoundary';
export class Skeleton extends Component {
render() {

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react';
import moment from 'moment';
import { Sigil } from '../../../../../logic/lib/sigil';
import { Sigil } from '~/logic/lib/sigil';
import CommentInput from './comment-input';
import { uxToHex, cite } from '../../../../../logic/lib/util';
import { uxToHex, cite } from '~/logic/lib/util';
export class CommentItem extends Component {
constructor(props) {

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react';
import { CommentItem } from './comment-item';
import CommentInput from './comment-input';
import { dateToDa } from '../../../../../logic/lib/util';
import { Spinner } from '../../../../components/Spinner';
import { dateToDa } from '~/logic/lib/util';
import { Spinner } from '~/views/components/Spinner';
export class Comments extends Component {
constructor(props) {

View File

@ -1,9 +1,9 @@
import React, { Component } from 'react';
import { SidebarSwitcher } from '../../../../components/SidebarSwitch';
import { Spinner } from '../../../../components/Spinner';
import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
import { Spinner } from '~/views/components/Spinner';
import { Link } from 'react-router-dom';
import { Controlled as CodeMirror } from 'react-codemirror2';
import { dateToDa } from '../../../../../logic/lib/util';
import { dateToDa } from '~/logic/lib/util';
import 'codemirror/mode/markdown/markdown';

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Spinner } from '../../../../components/Spinner';
import { Spinner } from '~/views/components/Spinner';
import urbitOb from 'urbit-ob';
export class JoinScreen extends Component {

Some files were not shown because too many files have changed in this diff Show More