interface: removed unused links files

This commit is contained in:
Logan Allen 2020-10-06 13:04:17 -05:00
parent 77b1db2d16
commit 97e1fa12a9
23 changed files with 7 additions and 1141 deletions

View File

@ -232,29 +232,6 @@ export function stringToTa(string) {
return '~.' + out; return '~.' + out;
} }
// used in Links
export function makeRoutePath(
resource,
page = 0,
url = null,
index = 0,
compage = 0
) {
let route = '/~link' + resource;
if (!url) {
if (page !== 0) {
route = route + '/' + page;
}
} else {
route = `${route}/${page}/${index}/${base64urlEncode(url)}`;
if (compage !== 0) {
route = route + '/' + compage;
}
}
return route;
}
export function amOwnerOfGroup(groupPath) { export function amOwnerOfGroup(groupPath) {
if (!groupPath) if (!groupPath)
return false; return false;

View File

@ -7,14 +7,13 @@ import { StoreState } from "~/logic/store/type";
import { uxToHex } from '~/logic/lib/util'; import { uxToHex } from '~/logic/lib/util';
import { Association, GraphNode } from "~/types"; import { Association, GraphNode } from "~/types";
import { RouteComponentProps } from "react-router-dom"; import { RouteComponentProps } from "react-router-dom";
import { LinkList } from "./components/link-list";
import { LinkDetail } from "./components/link-detail";
import { LinkItem } from "./components/lib/link-item"; import { LinkItem } from "./components/link-item";
import { LinkSubmit } from "./components/lib/link-submit"; import { LinkSubmit } from "./components/link-submit";
import { LinkPreview } from "./components/lib/link-preview"; import { LinkPreview } from "./components/link-preview";
import { CommentSubmit } from "./components/lib/comment-submit"; import { CommentSubmit } from "./components/comment-submit";
import { Comments } from "./components/lib/comments"; import { Comments } from "./components/comments";
import "./css/custom.css"; import "./css/custom.css";
type LinkResourceProps = StoreState & { type LinkResourceProps = StoreState & {

View File

@ -1,227 +0,0 @@
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Helmet from 'react-helmet';
import _ from 'lodash';
import './css/custom.css';
import { Skeleton } from './components/skeleton';
import { NewScreen } from './components/new';
import { SettingsScreen } from './components/settings';
import { MessageScreen } from './components/lib/message-screen';
import { LinkList } from './components/link-list';
import { LinkDetail } from './components/link-detail';
import {
amOwnerOfGroup,
base64urlDecode
} from '~/logic/lib/util';
export default class LinksApp extends Component {
componentDidMount() {
// preload spinner asset
new Image().src = '/~landscape/img/Spinner.png';
this.props.subscription.startApp('graph');
if (!this.props.sidebarShown) {
this.props.api.local.sidebarToggle();
}
}
componentWillUnmount() {
this.props.subscription.stopApp('graph');
}
render() {
const { props } = this;
const contacts = props.contacts ? props.contacts : {};
const groups = props.groups ? props.groups : {};
const associations =
props.associations ? props.associations : { graph: {}, contacts: {} };
const graphKeys = props.graphKeys || new Set([]);
const graphs = props.graphs || {};
const invites = props.invites ?
props.invites : {};
const {
api, sidebarShown, s3,
hideAvatars, hideNicknames, remoteContentPolicy
} = this.props;
return (
<>
<Helmet defer={false}>
<title>OS1 - Links</title>
</Helmet>
<Switch>
<Route exact path="/~link"
render={ (props) => (
<Skeleton
active="collections"
associations={associations}
invites={invites}
groups={groups}
rightPanelHide={true}
sidebarShown={sidebarShown}
api={api}
graphKeys={graphKeys}>
<MessageScreen text="Select or create a collection to begin." />
</Skeleton>
)}
/>
<Route exact path="/~link/new"
render={ (props) => (
<Skeleton
associations={associations}
invites={invites}
groups={groups}
sidebarShown={sidebarShown}
api={api}
graphKeys={graphKeys}>
<NewScreen
api={api}
graphKeys={graphKeys}
associations={associations}
groups={groups}
{...props}
/>
</Skeleton>
)}
/>
<Route exact path="/~link/:ship/:name/settings"
render={ (props) => {
const resourcePath =
`${props.match.params.ship}/${props.match.params.name}`;
const metPath = `/ship/~${resourcePath}`;
const resource =
associations.graph[metPath] ?
associations.graph[metPath] : { metadata: {} };
const contactDetails = contacts[resource['group-path']] || {};
const group = groups[resource['group-path']] || new Set([]);
const amOwner = amOwnerOfGroup(resource['group-path']);
const hasGraph = !!graphs[resourcePath];
return (
<Skeleton
associations={associations}
invites={invites}
groups={groups}
selected={resourcePath}
sidebarShown={sidebarShown}
graphKeys={graphKeys}
api={api}>
<SettingsScreen
sidebarShown={sidebarShown}
resource={resource}
contacts={contacts}
contactDetails={contactDetails}
graphResource={graphKeys.has(resourcePath)}
hasGraph={!!hasGraph}
group={group}
amOwner={amOwner}
resourcePath={resourcePath}
api={api}
{...props} />
</Skeleton>
);
}}
/>
<Route exact path="/~link/:ship/:name"
render={ (props) => {
const resourcePath =
`${props.match.params.ship}/${props.match.params.name}`;
const metPath = `/ship/~${resourcePath}`;
const resource =
associations.graph[metPath] ?
associations.graph[metPath] : { metadata: {} };
const contactDetails = contacts[resource['group-path']] || {};
const graph = graphs[resourcePath] || null;
return (
<Skeleton
associations={associations}
invites={invites}
groups={groups}
selected={resourcePath}
sidebarShown={sidebarShown}
sidebarHideMobile={true}
api={api}
graphKeys={graphKeys}>
<LinkList
{...props}
api={api}
s3={s3}
graph={graph}
graphResource={graphKeys.has(resourcePath)}
resourcePath={resourcePath}
metadata={resource.metadata}
contacts={contactDetails}
hideAvatars={hideAvatars}
hideNicknames={hideNicknames}
sidebarShown={sidebarShown}
ship={props.match.params.ship}
name={props.match.params.name}
/>
</Skeleton>
);
}}
/>
<Route exact path="/~link/:ship/:name/:index"
render={ (props) => {
const resourcePath =
`${props.match.params.ship}/${props.match.params.name}`;
const metPath = `/ship/~${resourcePath}`;
const resource =
associations.graph[metPath] ?
associations.graph[metPath] : { metadata: {} };
const contactDetails = contacts[resource['group-path']] || {};
const indexArr = props.match.params.index.split('-');
const graph = graphs[resourcePath] || null;
if (indexArr.length <= 1) {
return <div>Malformed URL</div>;
}
const index = parseInt(indexArr[1], 10);
const node = Boolean(graph) ? graph.get(index) : null;
return (
<Skeleton
associations={associations}
invites={invites}
groups={groups}
selected={resourcePath}
sidebarShown={sidebarShown}
sidebarHideMobile={true}
graphKeys={graphKeys}
api={api}>
<LinkDetail
{...props}
node={node}
graphResource={graphKeys.has(resourcePath)}
ship={props.match.params.ship}
name={props.match.params.name}
resource={resource}
contacts={contactDetails}
sidebarShown={sidebarShown}
api={api}
hideAvatars={hideAvatars}
hideNicknames={hideNicknames}
remoteContentPolicy={remoteContentPolicy} />
</Skeleton>
);
}}
/>
</Switch>
</>
);
}
}

View File

@ -1,29 +0,0 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
export class ChannelItem extends Component {
render() {
const { props } = this;
const selectedClass = (props.selected)
? 'bg-gray5 bg-gray1-d'
: 'pointer hover-bg-gray5 hover-bg-gray1-d';
const unseenCount = props.unseenCount > 0
? <span className="dib white bg-gray3 bg-gray2-d fw6 br1 absolute" style={{ padding: '1px 5px', right: 8 }}>{props.unseenCount}</span>
: null;
return (
<Link to={`/~link/${props.link}`}>
<div className={'w-100 v-mid f9 ph5 z1 pv1 relative ' + selectedClass}>
<p className="f9 dib">{props.name}</p>
<p className="f9 dib fr">
{unseenCount}
</p>
</div>
</Link>
);
}
}

View File

@ -1,109 +0,0 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { GroupItem } from './group-item';
import SidebarInvite from '~/views/components/Sidebar/SidebarInvite';
import { Welcome } from './welcome';
import { alphabetiseAssociations } from '~/logic/lib/util';
export const ChannelSidebar = (props) => {
const sidebarInvites = Object.keys(props.invites)
.map((uid) => {
return (
<SidebarInvite
key={uid}
invite={props.invites[uid]}
onAccept={() => props.api.invite.accept('/link', uid)}
onDecline={() => props.api.invite.decline('/link', uid)}
/>
);
});
const associations = props.associations.contacts ?
alphabetiseAssociations(props.associations.contacts) : {};
const graphAssoc = props.associations.graph || {};
const groupedChannels = {};
[...props.graphKeys].map((gKey) => {
const path = `/ship/~${gKey.split('/')[0]}/${gKey.split('/')[1]}`;
const groupPath = graphAssoc[path] ? graphAssoc[path]['group-path'] : '';
if (groupPath in associations) {
// managed
if (groupedChannels[groupPath]) {
const array = groupedChannels[groupPath];
array.push(path);
groupedChannels[groupPath] = array;
} else {
groupedChannels[groupPath] = [path];
}
} else {
// unmanaged
if (groupedChannels['/~/']) {
const array = groupedChannels['/~/'];
array.push(path);
groupedChannels['/~/'] = array;
} else {
groupedChannels['/~/'] = [path];
}
}
});
const groupedItems = Object.keys(associations).map((each, i) => {
const channels = groupedChannels[each];
if (!channels || channels.length === 0) { return; }
return (
<GroupItem
key={i + 1}
unmanaged={false}
association={associations[each]}
metadata={graphAssoc}
channels={channels}
selected={props.selected}
/>
);
});
if (groupedChannels['/~/'] && groupedChannels['/~/'].length !== 0) {
groupedItems.push(
<GroupItem
key={0}
unmanaged={true}
association={'/~/'}
metadata={graphAssoc}
channels={groupedChannels['/~/']}
selected={props.selected}
/>
);
}
const activeClasses = (props.active === 'collections') ? ' ' : 'dn-s ';
return (
<div className={
`bn br-m br-l br-xl b--gray4 b--gray1-d lh-copy h-100` +
`flex-shrink-0 mw5-m mw5-l mw5-xl pt3 pt0-m pt0-l pt0-xl relative ` +
activeClasses +
((props.sidebarShown) ? 'flex-basis-100-s flex-basis-30-ns' : 'dn')
}>
<div className="overflow-y-scroll h-100">
<div className="w-100 bg-transparent">
<Link
className="dib f9 pointer green2 gray4-d pa4"
to={'/~link/new'}>
New Collection
</Link>
</div>
<Welcome associations={props.associations} />
{sidebarInvites}
{groupedItems}
</div>
</div>
);
};

View File

@ -1,43 +0,0 @@
import React, { Component } from 'react';
import { ChannelItem } from './channel-item';
import { deSig } from '~/logic/lib/util';
export const GroupItem = (props) => {
const association = props.association ? props.association : {};
let title =
association['app-path'] ? association['app-path'] : 'Unmanaged Collections';
if (association.metadata && association.metadata.title) {
title = association.metadata.title !== ''
? association.metadata.title : title;
}
const channels = props.channels ? props.channels : [];
const unmanaged = props.unmanaged ? 'pt6' : 'pt1';
const channelItems = channels.map((each, i) => {
const meta = props.metadata[each];
if (!meta) { return null; }
const link = `${deSig(each.split('/')[2])}/${each.split('/')[3]}`;
const selected = (props.selected === each);
return (
<ChannelItem
key={each}
link={link}
selected={selected}
name={meta.metadata.title}
/>
);
});
return (
<div className={unmanaged}>
<p className="f9 ph4 pb2 gray3">{title}</p>
{channelItems}
</div>
);
};

View File

@ -1,55 +0,0 @@
import React, { Component } from 'react';
import { Sigil } from '~/logic/lib/sigil';
import { uxToHex, cite } from '~/logic/lib/util';
export class MemberElement extends Component {
onRemove() {
const { props } = this;
props.api.groups.remove(props.groupPath, [`~${props.ship}`]);
}
render() {
const { props } = this;
let actionElem;
if (props.ship === props.owner) {
actionElem = (
<p className="w-20 dib list-ship black white-d f8 c-default">
Host
</p>
);
} else if (props.amOwner && window.ship !== props.ship) {
actionElem = (
<a onClick={this.onRemove.bind(this)}
className="w-20 dib list-ship black white-d f8 pointer"
>
Ban
</a>
);
} else {
actionElem = (
<span></span>
);
}
const name = props.contact
? `${props.contact.nickname} (${cite(props.ship)})`
: `${cite(props.ship)}`;
const color = props.contact ? uxToHex(props.contact.color) : '000000';
const img = props.contact.avatar
? <img src={props.contact.avatar} height={32} width={32} className="dib" />
: <Sigil ship={props.ship} size={32} color={`#${color}`} />;
return (
<div className="flex mb2">
{img}
<p className={'w-70 mono list-ship dib v-mid black white-d ml2 nowrap f8'}
title={props.ship}
>
{name}
</p>
{actionElem}
</div>
);
}
}

View File

@ -1,15 +0,0 @@
import React, { Component } from 'react';
export class MessageScreen extends Component {
render() {
return (
<div className="h-100 w-100 overflow-x-hidden flex flex-column bg-white bg-gray0-d dn db-ns">
<div className="pl3 pr3 pt2 dt pb3 w-100 h-100">
<p className="f8 pt3 gray2 w-100 h-100 dtc v-mid tc">
{this.props.text}
</p>
</div>
</div>
);
}
}

View File

@ -1,37 +0,0 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { makeRoutePath } from '~/logic/lib/util';
export class Pagination extends Component {
render() {
const props = this.props;
const prevPage = (Number(props.page) - 1);
const nextPage = (Number(props.page) + 1);
const prevDisplay = ((props.currentPage > 0))
? 'dib absolute left-0'
: 'dn';
const nextDisplay = ((props.currentPage + 1) < props.totalPages)
? 'dib absolute right-0'
: 'dn';
return (
<div className="w-100 inter relative pv6">
<div className={prevDisplay + ' inter f8'}>
<Link to={makeRoutePath(props.resourcePath, prevPage)}>
&#60;- Previous Page
</Link>
</div>
<div className={nextDisplay + ' inter f8'}>
<Link to={makeRoutePath(props.resourcePath, nextPage)}>
Next Page -&gt;
</Link>
</div>
</div>
);
}
}
export default Pagination;

View File

@ -1,41 +0,0 @@
import React, { Component } from 'react';
export class Welcome extends Component {
constructor() {
super();
this.state = {
show: true
};
this.disableWelcome = this.disableWelcome.bind(this);
}
disableWelcome() {
this.setState({ show: false });
localStorage.setItem('urbit-link:wasWelcomed', JSON.stringify(true));
}
render() {
let wasWelcomed = localStorage.getItem('urbit-link:wasWelcomed');
if (wasWelcomed === null) {
localStorage.setItem('urbit-link:wasWelcomed', JSON.stringify(false));
return wasWelcomed = false;
} else {
wasWelcomed = JSON.parse(wasWelcomed);
}
const associations = this.props.associations ? this.props.associations : {};
return ((!wasWelcomed && this.state.show) && (associations.length !== 0)) ? (
<div className="ma4 pa2 bg-welcome-green bg-gray1-d white-d">
<p className="f8 lh-copy">Links are for collecting and discussing outside content. Each post is a URL and a comment thread.</p>
<p className="f8 pt2 dib bb pointer"
onClick={(() => this.disableWelcome())}
>
Close this
</p>
</div>
) : <div />;
}
}
export default Welcome;

View File

@ -1,100 +0,0 @@
import React, { useEffect } from 'react';
import { TabBar } from '~/views/components/chat-link-tabbar';
import { LinkPreview } from './lib/link-preview';
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) {
useEffect(() => {
props.api.graph.getGraph(
`~${props.match.params.ship}`,
props.match.params.name
);
});
return (
<div>Loading...</div>
);
}
if (!props.node) {
return (
<div>Not found</div>
);
}
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">
<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}`}
>
<h2
className="dib f9 fw4 lh-solid v-top black white-d"
style={{ width: 'max-content' }}
>
{`${title}`}
</h2>
</Link>
<TabBar
location={props.location}
settings={`/~link/${resourcePath}/settings`}
/>
</Box>
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
<div className="w-100 mw7">
<LinkPreview
resourcePath={resourcePath}
post={props.node.post}
nickname={nickname}
hideNicknames={props.hideNicknames}
commentNumber={props.node.children.size}
remoteContentPolicy={props.remoteContentPolicy}
/>
<div className="flex">
<CommentSubmit
name={props.name}
ship={props.ship}
api={props.api}
parentIndex={props.node.post.index}
/>
</div>
<Comments
comments={props.node.children}
resourcePath={resourcePath}
contacts={props.contacts}
api={props.api}
hideAvatars={props.hideAvatars}
hideNicknames={props.hideNicknames}
remoteContentPolicy={props.remoteContentPolicy}
/>
</div>
</div>
</div>
);
};

View File

@ -33,7 +33,7 @@ export const LinkItem = (props) => {
? <img src={props.avatar} height={36} width={36} className="dib" /> ? <img src={props.avatar} height={36} width={36} className="dib" />
: <Sigil ship={`~${author}`} size={36} color={'#' + props.color} />; : <Sigil ship={`~${author}`} size={36} color={'#' + props.color} />;
const baseUrl = props.baseUrl || `/~link/${resource}`; const baseUrl = props.baseUrl || `/~404/${resource}`;
return ( return (
<Row minWidth='0' flexShrink='0' width="100%" alignItems="center" py={3} bg="white"> <Row minWidth='0' flexShrink='0' width="100%" alignItems="center" py={3} bg="white">

View File

@ -1,91 +0,0 @@
import React, { useEffect } from "react";
import { TabBar } from '~/views/components/chat-link-tabbar';
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";
export const LinkList = (props) => {
const resource = `${props.ship}/${props.name}`;
const title = props.metadata.title || resource;
useEffect(() => {
props.api.graph.getGraph(
`~${props.match.params.ship}`,
props.match.params.name
);
}, [props.match.params.ship, props.match.params.name]);
if (!props.graph && props.graphResource) {
return <div>Loading...</div>;
}
if (!props.graph) {
return <div>Not found</div>;
}
return (
<div className="h-100 w-100 overflow-hidden flex flex-column">
<div
className="w-100 dn-m dn-l dn-xl inter pt4 pb6 pl3 f8"
style={{ height: "1rem" }}
>
<Link to="/~link">{"⟵ All Channels"}</Link>
</div>
<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} />
<h2
className="dib f9 fw4 pt2 lh-solid v-top black white-d"
style={{ width: 'max-content' }}>
{title}
</h2>
<TabBar
location={props.location}
settings={`/~link/${resource}/settings`}
/>
</Box>
<div className="w-100 mt6 flex justify-center overflow-y-scroll ph4 pb4">
<div className="w-100 mw7">
<div className="flex">
<LinkSubmit
name={props.name}
ship={props.ship}
api={props.api}
s3={props.s3} />
</div>
{ Array.from(props.graph).map(([date, node]) => {
const { nickname, color, avatar } =
getContactDetails(props.contacts[node?.post?.author]);
return (
<LinkItem
key={date}
resource={resource}
node={node}
nickname={nickname}
color={color}
avatar={avatar}
hideAvatars={props.hideAvatars}
hideNicknames={props.hideNicknames}
/>
);
})
}
</div>
</div>
</div>
);
};

View File

@ -1,8 +0,0 @@
import React, { Component } from 'react';
import { MessageScreen } from './lib/message-screen';
export class LoadingScreen extends Component {
render() {
return (<MessageScreen text="Loading..." />);
}
}

View File

@ -1,105 +0,0 @@
import React, { useCallback } from "react";
import { RouteComponentProps } from "react-router-dom";
import { Box, ManagedTextInputField as Input, Col } from "@tlon/indigo-react";
import { Formik, Form } from "formik";
import * as Yup from "yup";
import { AsyncButton } from "~/views/components/AsyncButton";
import { FormError } from "~/views/components/FormError";
import GroupSearch from "~/views/components/GroupSearch";
import GlobalApi from "~/logic/api/global";
import { stringToSymbol } from "~/logic/lib/util";
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
import { Associations } from "~/types/metadata-update";
import { Notebooks } from "~/types/publish-update";
import { Groups, GroupPolicy } from "~/types/group-update";
const formSchema = Yup.object({
name: Yup.string().required("Collection must have a name"),
description: Yup.string(),
group: Yup.string(),
});
export function NewScreen(props: object) {
const { history, api } = props;
const waiter = useWaitForProps(props, 5000);
const onSubmit = async (values: object, actions) => {
const resourceId = stringToSymbol(values.name);
try {
const { name, description, group } = values;
if (!!group) {
await props.api.graph.createManagedGraph(
resourceId,
name,
description,
group,
"link"
);
} else {
await props.api.graph.createUnmanagedGraph(
resourceId,
name,
description,
{ invite: { pending: [] } },
"link"
);
}
await waiter((p) => p?.graphKeys?.has(`${window.ship}/${resourceId}`));
actions.setStatus({ success: null });
history.push(`/~link/${window.ship}/${resourceId}`);
} catch (e) {
console.error(e);
actions.setStatus({ error: "Collection creation failed" });
}
};
return (
<Col p={3}>
<Box mb={4} color="black">New Collection</Box>
<Formik
validationSchema={formSchema}
initialValues={{ name: "", description: "", group: "" }}
onSubmit={onSubmit}>
<Form>
<Box
display="grid"
gridTemplateRows="auto"
gridRowGap={4}
gridTemplateColumns="300px">
<Input
id="name"
label="Name"
caption="Provide a name for your collection"
placeholder="eg. My Links"
/>
<Input
id="description"
label="Description"
caption="What's your collection about?"
placeholder="Collection description"
/>
<GroupSearch
id="group"
label="Group"
caption="What group is the collection for?"
associations={props.associations}
/>
<Box justifySelf="start">
<AsyncButton loadingText="Creating..." type="submit" border>
Create Collection
</AsyncButton>
</Box>
<FormError message="Collection creation failed" />
</Box>
</Form>
</Formik>
</Col>
);
}
export default NewScreen;

View File

@ -1,184 +0,0 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { LoadingScreen } from './loading';
import { Spinner } from '~/views/components/Spinner';
import { TabBar } from '~/views/components/chat-link-tabbar';
import SidebarSwitcher from '~/views/components/SidebarSwitch';
import { MetadataSettings } from '~/views/components/metadata/settings';
import { Box, Text, Button, Col, Row } from '@tlon/indigo-react';
export class SettingsScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
awaiting: false,
type: 'Editing'
};
this.renderDelete = this.renderDelete.bind(this);
this.changeLoading = this.changeLoading.bind(this);
}
componentDidUpdate() {
const { props, state } = this;
if (Boolean(state.isLoading) && !props.resource) {
this.setState({
isLoading: false
}, () => {
props.history.push('/~link');
});
}
}
changeLoading(isLoading, awaiting, type, closure) {
this.setState({
isLoading,
awaiting,
type
}, closure);
}
removeCollection() {
const { props } = this;
this.setState({
isLoading: true,
awaiting: true,
type: 'Removing'
});
props.api.graph.leaveGraph(
`~${props.match.params.ship}`,
props.match.params.name
);
}
deleteCollection() {
const { props } = this;
this.setState({
isLoading: true,
awaiting: true,
type: 'Deleting'
});
props.api.graph.deleteGraph(props.match.params.name);
}
renderRemove() {
const { props } = this;
if (props.amOwner) {
return null;
} else {
return (
<Box width='100%' mt='3'>
<Text display='block' mt='3' fontSize='1' mb='1'>Remove Collection</Text>
<Text display='block' fontSize='0' gray mb='4'>
Remove this collection from your collection list
</Text>
<Button onClick={this.removeCollection.bind(this)}>
Remove collection
</Button>
</Box>
);
}
}
renderDelete() {
const { props } = this;
if (!props.amOwner) {
return null;
} else {
return (
<Box width='100%' mt='3'>
<Text fontSize='1' mt='3' display='block' mb='1'>Delete collection</Text>
<Text fontSize='0' gray display='block' mb='4'>
Delete this collection, for you and all group members
</Text>
<Button primary onClick={this.deleteCollection.bind(this)} destructive mb='4'>
Delete collection
</Button>
</Box>
);
}
}
render() {
const { props, state } = this;
const title = props.resource.metadata.title || props.resourcePath;
if (
(!props.hasGraph || !props.resource.metadata.color)
&& props.graphResource
) {
return <LoadingScreen />;
} else if (!props.graphResource) {
props.history.push('/~link');
return <Box />;
}
return (
<Col height='100%' width='100' overflowX='hidden'>
<Box width='100%' display={['block', 'none']} pt='4' pb='6' pl='3' fontSize='1' height='1rem'>
<Link to="/~link">{'⟵ All Collections'}</Link>
</Box>
<Row
pl='12px'
pt='2'
borderBottom='1px solid'
borderColor='washedGray'
flexShrink='0'
overflowX={['scroll', 'auto']}
height='48px'
>
<SidebarSwitcher
sidebarShown={this.props.sidebarShown}
api={this.props.api}
/>
<Link className="dib f9 fw4 pt2 gray2 lh-solid"
to={`/~link/${props.resourcePath}`}>
<Text
display='inline-block'
fontSize='0'
verticalAlign='top'
width='max-content'>
{title}
</Text>
</Link>
<TabBar
location={props.location}
settings={`/~link/${props.resourcePath}/settings`}
/>
</Row>
<Box width='100' pl='3' mt='3'>
<Text display='block' fontSize='1' pb='2'>Collection Settings</Text>
{this.renderRemove()}
{this.renderDelete()}
<MetadataSettings
isOwner={props.amOwner}
changeLoading={this.changeLoading}
api={props.api}
association={props.resource}
resource="collection"
app="graph"
module="link"
/>
<Spinner
awaiting={this.state.awaiting}
classes="absolute right-1 bottom-1 pa2 ba b--black b--gray0-d white-d"
text={this.state.type}
/>
</Box>
</Col>
);
}
}

View File

@ -1,36 +0,0 @@
import React, { Component } from 'react';
import { ChannelSidebar } from './lib/channel-sidebar';
import ErrorBoundary from '~/views/components/ErrorBoundary';
export class Skeleton extends Component {
render() {
const { props } = this;
const rightPanelHide = props.rightPanelHide ? 'dn-s' : '';
const linkInvites = ('/link' in props.invites)
? props.invites['/link'] : {};
return (
<div className='absolute w-100 ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl'
style={{ height: 'calc(100% - 45px)' }}>
<div className='bg-white bg-gray0-d cf w-100 h-100 flex ba-m ba-l ba-xl b--gray4 b--gray1-d br1'>
<ChannelSidebar
active={props.active}
associations={props.associations}
invites={linkInvites}
groups={props.groups}
selected={props.selected}
sidebarShown={props.sidebarShown}
api={props.api}
graphKeys={props.graphKeys} />
<div className={'h-100 w-100 flex-auto relative ' + rightPanelHide}
style={{ flexGrow: 1 }}>
<ErrorBoundary>
{props.children}
</ErrorBoundary>
</div>
</div>
</div>
);
}
}

View File

@ -1,30 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Box } from '@tlon/indigo-react';
export const TabBar = (props) => {
const {
location,
settings,
} = props;
let setColor = '';
if (location.pathname.includes('/settings')) {
setColor = 'black white-d';
} else {
setColor = 'gray3';
}
return (
<Box display='inline-block' flexShrink='0' flexGrow='1'>
<Box display='inline-block' pt='9px' fontSize='0' pl='16px' pr='6'>
<Link
className={'no-underline ' + setColor}
to={settings}>
Settings
</Link>
</Box>
</Box>
);
};