mirror of
https://github.com/urbit/shrub.git
synced 2024-12-01 14:42:02 +03:00
Merge pull request #3639 from urbit/mp/interface/more-indigoifying
interface: indigo-reacting components, removing popout logic
This commit is contained in:
commit
87b97beaf8
@ -81,10 +81,10 @@ export function uxToHex(ux) {
|
||||
}
|
||||
|
||||
export function hexToUx(hex) {
|
||||
const ux = _.chain(hex.split(""))
|
||||
const ux = _.chain(hex.split(''))
|
||||
.chunk(4)
|
||||
.map((x) => _.dropWhile(x, (y) => y === 0).join(""))
|
||||
.join(".");
|
||||
.map(x => _.dropWhile(x, y => y === 0).join(''))
|
||||
.join('.');
|
||||
return `0x${ux}`;
|
||||
}
|
||||
|
||||
@ -236,28 +236,28 @@ export function stringToTa(string) {
|
||||
|
||||
export function makeRoutePath(
|
||||
resource,
|
||||
popout = false,
|
||||
page = 0,
|
||||
url = null,
|
||||
index = 0,
|
||||
compage = 0
|
||||
) {
|
||||
let route = "/~link" + (popout ? "/popout" : "") + resource;
|
||||
let route = '/~link' + resource;
|
||||
if (!url) {
|
||||
if (page !== 0) {
|
||||
route = route + "/" + page;
|
||||
route = route + '/' + page;
|
||||
}
|
||||
} else {
|
||||
route = `${route}/${page}/${index}/${base64urlEncode(url)}`;
|
||||
if (compage !== 0) {
|
||||
route = route + "/" + compage;
|
||||
route = route + '/' + compage;
|
||||
}
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
export function amOwnerOfGroup(groupPath) {
|
||||
if (!groupPath) return false;
|
||||
if (!groupPath)
|
||||
return false;
|
||||
const groupOwner = /(\/~)?\/~([a-z-]{3,})\/.*/.exec(groupPath)[2];
|
||||
return window.ship === groupOwner;
|
||||
}
|
||||
@ -265,20 +265,20 @@ export function amOwnerOfGroup(groupPath) {
|
||||
export function getContactDetails(contact) {
|
||||
const member = !contact;
|
||||
contact = contact || {
|
||||
nickname: "",
|
||||
nickname: '',
|
||||
avatar: null,
|
||||
color: "0x0",
|
||||
color: '0x0'
|
||||
};
|
||||
const nickname = contact.nickname || "";
|
||||
const color = uxToHex(contact.color || "0x0");
|
||||
const nickname = contact.nickname || '';
|
||||
const color = uxToHex(contact.color || '0x0');
|
||||
const avatar = contact.avatar || null;
|
||||
return { nickname, color, member, avatar };
|
||||
}
|
||||
|
||||
export function stringToSymbol(str) {
|
||||
let result = '';
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var n = str.charCodeAt(i);
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const n = str.charCodeAt(i);
|
||||
if (((n >= 97) && (n <= 122)) ||
|
||||
((n >= 48) && (n <= 57))) {
|
||||
result += str[i];
|
||||
@ -298,12 +298,12 @@ export function stringToSymbol(str) {
|
||||
|
||||
export function scrollIsAtTop(container) {
|
||||
if (
|
||||
(navigator.userAgent.includes("Safari") &&
|
||||
navigator.userAgent.includes("Chrome")) ||
|
||||
navigator.userAgent.includes("Firefox")
|
||||
(navigator.userAgent.includes('Safari') &&
|
||||
navigator.userAgent.includes('Chrome')) ||
|
||||
navigator.userAgent.includes('Firefox')
|
||||
) {
|
||||
return container.scrollTop === 0;
|
||||
} else if (navigator.userAgent.includes("Safari")) {
|
||||
} else if (navigator.userAgent.includes('Safari')) {
|
||||
return (
|
||||
container.scrollHeight + Math.round(container.scrollTop) <=
|
||||
container.clientHeight + 10
|
||||
@ -315,15 +315,15 @@ export function scrollIsAtTop(container) {
|
||||
|
||||
export function scrollIsAtBottom(container) {
|
||||
if (
|
||||
(navigator.userAgent.includes("Safari") &&
|
||||
navigator.userAgent.includes("Chrome")) ||
|
||||
navigator.userAgent.includes("Firefox")
|
||||
(navigator.userAgent.includes('Safari') &&
|
||||
navigator.userAgent.includes('Chrome')) ||
|
||||
navigator.userAgent.includes('Firefox')
|
||||
) {
|
||||
return (
|
||||
container.scrollHeight - Math.round(container.scrollTop) <=
|
||||
container.clientHeight + 10
|
||||
);
|
||||
} else if (navigator.userAgent.includes("Safari")) {
|
||||
} else if (navigator.userAgent.includes('Safari')) {
|
||||
return container.scrollTop === 0;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -220,9 +220,9 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/~chat/(popout)?/room/(~)?/:ship/:station+"
|
||||
path="/~chat/room/(~)?/:ship/:station+"
|
||||
render={(props) => {
|
||||
let station = `/${props.match.params.ship}/${props.match.params.station}`;
|
||||
const station = `/${props.match.params.ship}/${props.match.params.station}`;
|
||||
const mailbox = inbox[station] || {
|
||||
config: {
|
||||
read: 0,
|
||||
@ -247,14 +247,11 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
|
||||
const group = groups[association['group-path']] || groupBunts.group();
|
||||
|
||||
const popout = props.match.url.includes('/popout/');
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
sidebarHideOnMobile={true}
|
||||
popout={popout}
|
||||
sidebarShown={sidebarShown}
|
||||
sidebar={renderChannelSidebar(props, station)}
|
||||
>
|
||||
@ -271,7 +268,6 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
group={group}
|
||||
pendingMessages={pendingMessages}
|
||||
s3={s3}
|
||||
popout={popout}
|
||||
sidebarShown={sidebarShown}
|
||||
chatInitialized={chatInitialized}
|
||||
hideAvatars={hideAvatars}
|
||||
@ -285,10 +281,9 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/~chat/(popout)?/settings/(~)?/:ship/:station+"
|
||||
path="/~chat/settings/(~)?/:ship/:station+"
|
||||
render={(props) => {
|
||||
let station = `/${props.match.params.ship}/${props.match.params.station}`;
|
||||
const popout = props.match.url.includes('/popout/');
|
||||
|
||||
const association =
|
||||
station in associations['chat'] ? associations.chat[station] : {};
|
||||
@ -299,7 +294,6 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
sidebarHideOnMobile={true}
|
||||
popout={popout}
|
||||
sidebarShown={sidebarShown}
|
||||
sidebar={renderChannelSidebar(props, station)}
|
||||
>
|
||||
@ -313,7 +307,6 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
associations={associations.contacts}
|
||||
api={api}
|
||||
inbox={inbox}
|
||||
popout={popout}
|
||||
sidebarShown={sidebarShown}
|
||||
/>
|
||||
</Skeleton>
|
||||
|
@ -33,7 +33,6 @@ type ChatScreenProps = RouteComponentProps<{
|
||||
group: Group;
|
||||
pendingMessages: Map<Path, Envelope[]>;
|
||||
s3: any;
|
||||
popout: boolean;
|
||||
sidebarShown: boolean;
|
||||
chatInitialized: boolean;
|
||||
envelopes: Envelope[];
|
||||
@ -131,7 +130,7 @@ export class ChatScreen extends Component<ChatScreenProps, ChatScreenState> {
|
||||
|
||||
const unreadCount = props.mailboxSize - props.read;
|
||||
const unreadMsg = unreadCount > 0 && props.envelopes[unreadCount - 1];
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
key={props.station}
|
||||
|
@ -6,7 +6,6 @@ import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
|
||||
import { deSig } from '~/logic/lib/util';
|
||||
|
||||
const ChatHeader = (props) => {
|
||||
const isInPopout = props.popout ? 'popout/' : '';
|
||||
const group = Array.from(props.group.members);
|
||||
let title = props.station.substr(1);
|
||||
if (props.association &&
|
||||
@ -32,11 +31,10 @@ const ChatHeader = (props) => {
|
||||
>
|
||||
<SidebarSwitcher
|
||||
sidebarShown={props.sidebarShown}
|
||||
popout={props.popout}
|
||||
api={props.api}
|
||||
/>
|
||||
<Link
|
||||
to={'/~chat/' + isInPopout + 'room' + props.station}
|
||||
to={'/~chat/' + 'room' + props.station}
|
||||
className="pt2 white-d"
|
||||
>
|
||||
<h2
|
||||
@ -51,9 +49,7 @@ const ChatHeader = (props) => {
|
||||
</Link>
|
||||
<TabBar
|
||||
location={props.location}
|
||||
popoutHref={`/~chat/popout/room${props.station}`}
|
||||
settings={`/~chat/${isInPopout}settings${props.station}`}
|
||||
popout={props.popout}
|
||||
settings={`/~chat/settings${props.station}`}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
|
@ -85,7 +85,7 @@ export default class ChatMessage extends Component<ChatMessageProps> {
|
||||
isLastMessage,
|
||||
unreadMarkerRef
|
||||
} = this.props;
|
||||
|
||||
|
||||
const renderSigil = Boolean((nextMsg && msg.author !== nextMsg.author) || !nextMsg || msg.number === 1);
|
||||
const dayBreak = nextMsg && new Date(msg.when).getDate() !== new Date(nextMsg.when).getDate();
|
||||
|
||||
@ -221,7 +221,7 @@ export class MessageWithSigil extends PureComponent<MessageProps> {
|
||||
|
||||
export const MessageWithoutSigil = ({ timestamp, msg, remoteContentPolicy, measure }) => (
|
||||
<>
|
||||
<p className="child ph1 mono f9 gray2 dib">{timestamp}</p>
|
||||
<p className="child pr1 mono f9 gray2 dib">{timestamp}</p>
|
||||
<div className="fr clamp-message white-d pr3 lh-copy" style={{ flexGrow: 1 }}>
|
||||
<MessageContent content={msg.letter} remoteContentPolicy={remoteContentPolicy} measure={measure}/>
|
||||
</div>
|
||||
|
@ -1,11 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Button, Text, Box } from '@tlon/indigo-react';
|
||||
|
||||
export const DeleteButton = memo(({ isOwner, station, changeLoading, association, contacts, api, history }) => {
|
||||
const leaveButtonClasses = (!isOwner) ? 'pointer' : 'c-default';
|
||||
const deleteButtonClasses = (isOwner) ?
|
||||
'b--red2 red2 pointer bg-gray0-d' :
|
||||
'b--gray3 gray3 bg-gray0-d c-default';
|
||||
|
||||
const deleteChat = () => {
|
||||
changeLoading(
|
||||
true,
|
||||
@ -13,7 +9,7 @@ export const DeleteButton = memo(({ isOwner, station, changeLoading, association
|
||||
isOwner ? 'Deleting chat...' : 'Leaving chat...',
|
||||
() => {
|
||||
api.chat.delete(station).then(() => {
|
||||
history.push("/~chat");
|
||||
history.push('/~chat');
|
||||
});
|
||||
}
|
||||
);
|
||||
@ -23,34 +19,30 @@ export const DeleteButton = memo(({ isOwner, station, changeLoading, association
|
||||
const unmanagedVillage = !contacts[groupPath];
|
||||
|
||||
return (
|
||||
<div className="w-100 cf">
|
||||
<div className={'w-100 fl mt3 ' + ((isOwner) ? 'o-30' : '')}>
|
||||
<p className="f8 mt3 lh-copy db">Leave Chat</p>
|
||||
<p className="f9 gray2 db mb4">
|
||||
<Box width='100%'>
|
||||
<Box width='100%' mt='3' opacity={(isOwner) ? '0.3' : '1'}>
|
||||
<Text fontSize='1' mt='3' display='block' mb='1'>Leave Chat</Text>
|
||||
<Text fontSize='0' gray display='block' mb='4'>
|
||||
Remove this chat from your chat list.{' '}
|
||||
{unmanagedVillage
|
||||
{unmanagedVillage
|
||||
? 'You will need to request for access again'
|
||||
: 'You will need to join again from the group page.'
|
||||
: 'You will need to join again from the group page'
|
||||
}
|
||||
</p>
|
||||
<a onClick={(!isOwner) ? deleteChat : null}
|
||||
className={
|
||||
'dib f9 black gray4-d bg-gray0-d ba pa2 b--black b--gray1-d ' +
|
||||
leaveButtonClasses
|
||||
}>
|
||||
</Text>
|
||||
<Button onClick={(!isOwner) ? deleteChat : null}>
|
||||
Leave this chat
|
||||
</a>
|
||||
</div>
|
||||
<div className={'w-100 fl mt3 ' + ((!isOwner) ? 'o-30' : '')}>
|
||||
<p className="f8 mt3 lh-copy db">Delete Chat</p>
|
||||
<p className="f9 gray2 db mb4">
|
||||
</Button>
|
||||
</Box>
|
||||
<Box width='100%' mt='3' opacity={(isOwner) ? '0.3' : '1'}>
|
||||
<Text display='block' fontSize='1' mt='3' mb='1'>Delete Chat</Text>
|
||||
<Text display='block' gray fontSize='0' mb='4'>
|
||||
Permanently delete this chat.{' '}
|
||||
All current members will no longer see this chat.
|
||||
</p>
|
||||
<a onClick={(isOwner) ? deleteChat : null}
|
||||
className={'dib f9 ba pa2 ' + deleteButtonClasses}
|
||||
>Delete this chat</a>
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
<Button destructive onClick={(isOwner) ? deleteChat : null}>Delete this chat</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
DeleteButton.displayName = 'DeleteButton';
|
||||
|
@ -2,9 +2,9 @@ import React, { Component } from 'react';
|
||||
import Toggle from '~/views/components/toggle';
|
||||
import { InviteSearch } from '~/views/components/InviteSearch';
|
||||
|
||||
import { Button, Text, Box } from '@tlon/indigo-react';
|
||||
|
||||
export class GroupifyButton extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@ -26,23 +26,23 @@ export class GroupifyButton extends Component {
|
||||
this.setState({ inclusive: Boolean(event.target.checked) });
|
||||
}
|
||||
|
||||
renderInclusiveToggle() {
|
||||
renderInclusiveToggle(inclusive) {
|
||||
return this.state.targetGroup ? (
|
||||
<div className="mt4">
|
||||
<Box mt='4'>
|
||||
<Toggle
|
||||
boolean={inclusive}
|
||||
change={this.changeInclusive.bind(this)}
|
||||
/>
|
||||
<span className="dib f9 white-d inter ml3">
|
||||
<Text display='inline-block' fontSize='0' ml='3'>
|
||||
Add all members to group
|
||||
</span>
|
||||
<p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}>
|
||||
</Text>
|
||||
<Text display='block' fontSize='0' gray pt='1' pl='40px'>
|
||||
Add chat members to the group if they aren't in it yet
|
||||
</p>
|
||||
</div>
|
||||
) : <div />;
|
||||
</Text>
|
||||
</Box>
|
||||
) : <Box />;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { inclusive, targetGroup } = this.state;
|
||||
const {
|
||||
@ -65,12 +65,12 @@ export class GroupifyButton extends Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'w-100 fl mt3'} style={{ maxWidth: '29rem' }}>
|
||||
<p className="f8 mt3 lh-copy db">Convert Chat</p>
|
||||
<p className="f9 gray2 db mb4">
|
||||
<Box width='100%' mt='3' maxWidth='29rem'>
|
||||
<Text display='block' fontSize='1' mt='3' mb='1'>Convert Chat</Text>
|
||||
<Text gray display='block' mb='4' fontSize='0'>
|
||||
Convert this chat into a group with associated chat, or select a
|
||||
group to add this chat to.
|
||||
</p>
|
||||
group to add this chat to
|
||||
</Text>
|
||||
<InviteSearch
|
||||
groups={groups}
|
||||
contacts={contacts}
|
||||
@ -83,8 +83,8 @@ export class GroupifyButton extends Component {
|
||||
}}
|
||||
setInvite={this.changeTargetGroup.bind(this)}
|
||||
/>
|
||||
{this.renderInclusiveToggle()}
|
||||
<a onClick={() => {
|
||||
{this.renderInclusiveToggle(inclusive)}
|
||||
<Button mt='3' onClick={() => {
|
||||
changeLoading(true, true, 'Converting to group...', () => {
|
||||
api.chat.groupify(
|
||||
station, targetGroup, inclusive
|
||||
@ -93,11 +93,8 @@ export class GroupifyButton extends Component {
|
||||
});
|
||||
});
|
||||
}}
|
||||
className={
|
||||
'dib f9 black gray4-d bg-gray0-d ba pa2 mt4 b--black ' +
|
||||
'b--gray1-d pointer'
|
||||
}>Convert to group</a>
|
||||
</div>
|
||||
>Convert to group</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import ChatHeader from './lib/ChatHeader';
|
||||
import { DeleteButton } from './lib/delete-button';
|
||||
import { GroupifyButton } from './lib/groupify-button';
|
||||
|
||||
import { Text, Col, Box } from '@tlon/indigo-react';
|
||||
|
||||
export class SettingsScreen extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -59,7 +61,6 @@ export class SettingsScreen extends Component {
|
||||
}
|
||||
|
||||
renderNormal() {
|
||||
const { state } = this;
|
||||
const {
|
||||
associations,
|
||||
association,
|
||||
@ -74,7 +75,7 @@ export class SettingsScreen extends Component {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<h2 className="f8 pb2">Chat Settings</h2>
|
||||
<Text display='block' pb='2' fontSize='1'>Chat Settings</Text>
|
||||
<GroupifyButton
|
||||
isOwner={isOwner}
|
||||
association={association}
|
||||
@ -116,21 +117,13 @@ export class SettingsScreen extends Component {
|
||||
group,
|
||||
association,
|
||||
station,
|
||||
popout,
|
||||
sidebarShown,
|
||||
match,
|
||||
location
|
||||
} = this.props;
|
||||
|
||||
const isInPopout = popout ? "popout/" : "";
|
||||
const title =
|
||||
( association &&
|
||||
('metadata' in association) &&
|
||||
(association.metadata.title !== '')
|
||||
) ? association.metadata.title : station.substr(1);
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column white-d">
|
||||
<Col height='100%' width='100%' overflowX='hidden'>
|
||||
<ChatHeader
|
||||
match={match}
|
||||
location={location}
|
||||
@ -139,11 +132,11 @@ export class SettingsScreen extends Component {
|
||||
association={association}
|
||||
station={station}
|
||||
sidebarShown={sidebarShown}
|
||||
popout={popout} />
|
||||
<div className="w-100 pl3 mt4 cf">
|
||||
/>
|
||||
<Box width='100%' pl='3' mt='3'>
|
||||
{(state.isLoading) ? this.renderLoading() : this.renderNormal() }
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import ErrorBoundary from '~/views/components/ErrorBoundary';
|
||||
export class Skeleton extends Component {
|
||||
render() {
|
||||
// sidebar and chat panel conditional classes
|
||||
const sidebarHide = (!this.props.sidebarShown || this.props.popout)
|
||||
const sidebarHide = (!this.props.sidebarShown)
|
||||
? 'dn' : '';
|
||||
|
||||
const sidebarHideOnMobile = this.props.sidebarHideOnMobile
|
||||
@ -22,18 +22,11 @@ export class Skeleton extends Component {
|
||||
'w-100 inter pt4 f8': !this.props.chatHideOnMobile
|
||||
});
|
||||
|
||||
// popout switches out window chrome and borders
|
||||
const popoutWindow = this.props.popout
|
||||
? '' : 'ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl';
|
||||
|
||||
const popoutBorder = this.props.popout
|
||||
? '' : 'ba-m ba-l ba-xl b--gray4 b--gray1-d br1 ';
|
||||
|
||||
return (
|
||||
// app outer skeleton
|
||||
<div className={'h-100 w-100 ' + popoutWindow}>
|
||||
<div className='h-100 w-100 ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl'>
|
||||
{/* app window borders */}
|
||||
<div className={ 'bg-white bg-gray0-d cf w-100 flex h-100 ' + popoutBorder }>
|
||||
<div className='bg-white bg-gray0-d cf w-100 flex h-100 ba-m ba-l ba-xl b--gray4 b--gray1-d br1'>
|
||||
{/* sidebar skeleton, hidden on mobile when in chat panel */}
|
||||
<div
|
||||
className={
|
||||
|
@ -1,9 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Route, Link } from 'react-router-dom';
|
||||
import classnames from 'classnames';
|
||||
import { Route } from 'react-router-dom';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
import { Popout } from './components/lib/icons/popout';
|
||||
import { History } from './components/history';
|
||||
import { Input } from './components/input';
|
||||
|
||||
@ -54,16 +52,8 @@ export default class DojoApp extends Component {
|
||||
>
|
||||
<Route
|
||||
exact
|
||||
path="/~dojo/:popout?"
|
||||
path="/~dojo/"
|
||||
render={(props) => {
|
||||
const popout = Boolean(props.match.params.popout);
|
||||
|
||||
const popoutClasses = classnames({
|
||||
'mh4-m mh4-l mh4-xl': !popout,
|
||||
'mb4-m mb4-l mb4-xl': !popout,
|
||||
'ba-m ba-l ba-xl': !popout
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-100 h-100 flex-m flex-l flex-xl">
|
||||
<div
|
||||
@ -75,14 +65,13 @@ export default class DojoApp extends Component {
|
||||
className={
|
||||
'pa3 bg-white bg-gray0-d black white-d mono w-100 f8 relative' +
|
||||
' h-100-m40-s b--gray2 br1 flex-auto flex flex-column ' +
|
||||
popoutClasses
|
||||
'mh4-m mh4-l mh4-xl mb4-m mb4-l mb4-xl ba-m ba-l ba-xl'
|
||||
}
|
||||
style={{
|
||||
lineHeight: '1.4',
|
||||
cursor: 'text'
|
||||
}}
|
||||
>
|
||||
<Popout popout={popout} />
|
||||
<History commandLog={this.state.txt} />
|
||||
<Input
|
||||
ship={this.props.ship}
|
||||
|
@ -1,29 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export class Popout extends Component {
|
||||
render() {
|
||||
const hidePopoutIcon = this.props.popout
|
||||
? 'dn-m dn-l dn-xl'
|
||||
: 'dib-m dib-l dib-xl';
|
||||
return (
|
||||
<div
|
||||
className="db tr z-2"
|
||||
style={{
|
||||
right: 16,
|
||||
top: 16
|
||||
}}
|
||||
>
|
||||
<a href="/~dojo/popout" target="_blank">
|
||||
<img
|
||||
className={'flex-shrink-0 dn ' + hidePopoutIcon}
|
||||
src="/~dojo/img/popout.png"
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Popout;
|
@ -24,7 +24,7 @@ export function InvitePopover(props: InvitePopoverProps) {
|
||||
const { baseUrl, api, association } = props;
|
||||
|
||||
const relativePath = (p: string) => baseUrl + p;
|
||||
const { title } = association.metadata;
|
||||
const { title } = association?.metadata || '';
|
||||
const innerRef = useRef(null);
|
||||
const history = useHistory();
|
||||
|
||||
|
@ -49,7 +49,6 @@ export function LinkResource(props: LinkResourceProps) {
|
||||
? associations.graph[appPath]
|
||||
: { metadata: {} };
|
||||
const contactDetails = contacts[resource["group-path"]] || {};
|
||||
const popout = props.match.url.includes("/popout/");
|
||||
const graph = graphs[resourcePath] || null;
|
||||
|
||||
useEffect(() => {
|
||||
@ -131,7 +130,6 @@ export function LinkResource(props: LinkResourceProps) {
|
||||
comments={node.children}
|
||||
resourcePath={resourcePath}
|
||||
contacts={contactDetails}
|
||||
popout={false}
|
||||
api={api}
|
||||
hideAvatars={hideAvatars}
|
||||
hideNicknames={hideNicknames}
|
||||
|
@ -91,11 +91,10 @@ export default class LinksApp extends Component {
|
||||
</Skeleton>
|
||||
)}
|
||||
/>
|
||||
<Route exact path="/~link/(popout)?/:ship/:name/settings"
|
||||
<Route exact path="/~link/:ship/:name/settings"
|
||||
render={ (props) => {
|
||||
const resourcePath =
|
||||
const resourcePath =
|
||||
`${props.match.params.ship}/${props.match.params.name}`;
|
||||
const popout = props.match.url.includes('/popout/');
|
||||
const metPath = `/ship/~${resourcePath}`;
|
||||
const resource =
|
||||
associations.graph[metPath] ?
|
||||
@ -113,7 +112,6 @@ export default class LinksApp extends Component {
|
||||
groups={groups}
|
||||
selected={resourcePath}
|
||||
sidebarShown={sidebarShown}
|
||||
popout={popout}
|
||||
graphKeys={graphKeys}
|
||||
api={api}>
|
||||
<SettingsScreen
|
||||
@ -126,16 +124,15 @@ export default class LinksApp extends Component {
|
||||
group={group}
|
||||
amOwner={amOwner}
|
||||
resourcePath={resourcePath}
|
||||
popout={popout}
|
||||
api={api}
|
||||
{...props} />
|
||||
</Skeleton>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route exact path="/~link/(popout)?/:ship/:name"
|
||||
<Route exact path="/~link/:ship/:name"
|
||||
render={ (props) => {
|
||||
const resourcePath =
|
||||
const resourcePath =
|
||||
`${props.match.params.ship}/${props.match.params.name}`;
|
||||
const metPath = `/ship/~${resourcePath}`;
|
||||
const resource =
|
||||
@ -143,7 +140,6 @@ export default class LinksApp extends Component {
|
||||
associations.graph[metPath] : { metadata: {} };
|
||||
|
||||
const contactDetails = contacts[resource['group-path']] || {};
|
||||
const popout = props.match.url.includes('/popout/');
|
||||
const graph = graphs[resourcePath] || null;
|
||||
|
||||
return (
|
||||
@ -154,7 +150,6 @@ export default class LinksApp extends Component {
|
||||
selected={resourcePath}
|
||||
sidebarShown={sidebarShown}
|
||||
sidebarHideMobile={true}
|
||||
popout={popout}
|
||||
api={api}
|
||||
graphKeys={graphKeys}>
|
||||
<LinkList
|
||||
@ -164,7 +159,6 @@ export default class LinksApp extends Component {
|
||||
graph={graph}
|
||||
graphResource={graphKeys.has(resourcePath)}
|
||||
resourcePath={resourcePath}
|
||||
popout={popout}
|
||||
metadata={resource.metadata}
|
||||
contacts={contactDetails}
|
||||
hideAvatars={hideAvatars}
|
||||
@ -177,15 +171,14 @@ export default class LinksApp extends Component {
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route exact path="/~link/(popout)?/:ship/:name/:index"
|
||||
<Route exact path="/~link/:ship/:name/:index"
|
||||
render={ (props) => {
|
||||
const resourcePath =
|
||||
const resourcePath =
|
||||
`${props.match.params.ship}/${props.match.params.name}`;
|
||||
const metPath = `/ship/~${resourcePath}`;
|
||||
const resource =
|
||||
associations.graph[metPath] ?
|
||||
associations.graph[metPath] : { metadata: {} };
|
||||
const popout = props.match.url.includes('/popout/');
|
||||
|
||||
const contactDetails = contacts[resource['group-path']] || {};
|
||||
|
||||
@ -197,7 +190,7 @@ export default class LinksApp extends Component {
|
||||
}
|
||||
|
||||
const index = parseInt(indexArr[1], 10);
|
||||
const node = !!graph ? graph.get(index) : null;
|
||||
const node = Boolean(graph) ? graph.get(index) : null;
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
@ -207,7 +200,6 @@ export default class LinksApp extends Component {
|
||||
selected={resourcePath}
|
||||
sidebarShown={sidebarShown}
|
||||
sidebarHideMobile={true}
|
||||
popout={popout}
|
||||
graphKeys={graphKeys}
|
||||
api={api}>
|
||||
<LinkDetail
|
||||
@ -218,7 +210,6 @@ export default class LinksApp extends Component {
|
||||
name={props.match.params.name}
|
||||
resource={resource}
|
||||
contacts={contactDetails}
|
||||
popout={popout}
|
||||
sidebarShown={sidebarShown}
|
||||
api={api}
|
||||
hideAvatars={hideAvatars}
|
||||
|
@ -83,14 +83,13 @@ export const ChannelSidebar = (props) => {
|
||||
}
|
||||
|
||||
const activeClasses = (props.active === 'collections') ? ' ' : 'dn-s ';
|
||||
const hiddenClasses = !!props.popout ? false : props.sidebarShown;
|
||||
|
||||
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 +
|
||||
((hiddenClasses) ? 'flex-basis-100-s flex-basis-30-ns' : 'dn')
|
||||
((props.sidebarShown) ? 'flex-basis-100-s flex-basis-30-ns' : 'dn')
|
||||
}>
|
||||
<div className="overflow-y-scroll h-100">
|
||||
<div className="w-100 bg-transparent">
|
||||
|
@ -20,12 +20,12 @@ export class Pagination extends Component {
|
||||
return (
|
||||
<div className="w-100 inter relative pv6">
|
||||
<div className={prevDisplay + ' inter f8'}>
|
||||
<Link to={makeRoutePath(props.resourcePath, props.popout, prevPage)}>
|
||||
<Link to={makeRoutePath(props.resourcePath, prevPage)}>
|
||||
<- Previous Page
|
||||
</Link>
|
||||
</div>
|
||||
<div className={nextDisplay + ' inter f8'}>
|
||||
<Link to={makeRoutePath(props.resourcePath, props.popout, nextPage)}>
|
||||
<Link to={makeRoutePath(props.resourcePath, nextPage)}>
|
||||
Next Page ->
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -45,7 +45,6 @@ export const LinkDetail = (props) => {
|
||||
style={{ height: 48 }}>
|
||||
<SidebarSwitcher
|
||||
sidebarShown={props.sidebarShown}
|
||||
popout={props.popout}
|
||||
api={props.api}
|
||||
/>
|
||||
<Link className="dib f9 fw4 pt2 gray2 lh-solid"
|
||||
@ -58,8 +57,6 @@ export const LinkDetail = (props) => {
|
||||
</Link>
|
||||
<TabBar
|
||||
location={props.location}
|
||||
popout={props.popout}
|
||||
popoutHref={`/~link/popout/${resourcePath}/${props.match.params.index}`}
|
||||
settings={`/~link/${resourcePath}/settings`}
|
||||
/>
|
||||
</div>
|
||||
@ -84,7 +81,6 @@ export const LinkDetail = (props) => {
|
||||
comments={props.node.children}
|
||||
resourcePath={resourcePath}
|
||||
contacts={props.contacts}
|
||||
popout={props.popout}
|
||||
api={props.api}
|
||||
hideAvatars={props.hideAvatars}
|
||||
hideNicknames={props.hideNicknames}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Component, useEffect } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import { TabBar } from '~/views/components/chat-link-tabbar';
|
||||
import { SidebarSwitcher } from '~/views/components/SidebarSwitch';
|
||||
@ -44,7 +44,6 @@ export const LinkList = (props) => {
|
||||
>
|
||||
<SidebarSwitcher
|
||||
sidebarShown={props.sidebarShown}
|
||||
popout={props.popout}
|
||||
api={props.api} />
|
||||
<h2
|
||||
className="dib f9 fw4 pt2 lh-solid v-top black white-d"
|
||||
@ -53,8 +52,6 @@ export const LinkList = (props) => {
|
||||
</h2>
|
||||
<TabBar
|
||||
location={props.location}
|
||||
popout={props.popout}
|
||||
popoutHref={`/~link/popout/${resource}`}
|
||||
settings={`/~link/${resource}/settings`}
|
||||
/>
|
||||
</div>
|
||||
|
@ -9,6 +9,8 @@ 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);
|
||||
@ -77,16 +79,15 @@ export class SettingsScreen extends Component {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<div className="w-100 fl mt3">
|
||||
<p className="f8 mt3 lh-copy db">Remove Collection</p>
|
||||
<p className="f9 gray2 db mb4">
|
||||
Remove this collection from your collection list.
|
||||
</p>
|
||||
<a onClick={this.removeCollection.bind(this)}
|
||||
className="dib f9 black gray4-d bg-gray0-d ba pa2 b--black b--gray1-d pointer">
|
||||
<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
|
||||
</a>
|
||||
</div>
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -98,16 +99,15 @@ export class SettingsScreen extends Component {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<div className="w-100 fl mt3">
|
||||
<p className="f8 mt3 lh-copy db">Delete Collection</p>
|
||||
<p className="f9 gray2 db mb4">
|
||||
Delete this collection, for you and all group members.
|
||||
</p>
|
||||
<a onClick={this.deleteCollection.bind(this)}
|
||||
className="dib f9 ba pa2 b--red2 red2 pointer bg-gray0-d mb4">
|
||||
<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
|
||||
</a>
|
||||
</div>
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -123,43 +123,44 @@ export class SettingsScreen extends Component {
|
||||
return <LoadingScreen />;
|
||||
} else if (!props.graphResource) {
|
||||
props.history.push('/~link');
|
||||
return <div></div>;
|
||||
return <Box />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column white-d">
|
||||
<div className="w-100 dn-m dn-l dn-xl inter pt4 pb6 pl3 f8"
|
||||
style={{ height: '1rem' }}>
|
||||
<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>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
"pl4 pt2 bb b--gray4 b--gray1-d flex relative overflow-x-scroll " +
|
||||
"overflow-x-auto-l overflow-x-auto-xl flex-shrink-0"
|
||||
}
|
||||
style={{ height: 48 }}>
|
||||
</Box>
|
||||
<Row
|
||||
pl='12px'
|
||||
pt='2'
|
||||
borderBottom='1px solid'
|
||||
borderColor='washedGray'
|
||||
flexShrink='0'
|
||||
overflowX={['scroll', 'auto']}
|
||||
height='48px'
|
||||
>
|
||||
<SidebarSwitcher
|
||||
sidebarShown={this.props.sidebarShown}
|
||||
popout={this.props.popout}
|
||||
api={this.props.api}
|
||||
/>
|
||||
<Link className="dib f9 fw4 pt2 gray2 lh-solid"
|
||||
to={`/~link/${props.resourcePath}`}>
|
||||
<h2
|
||||
className="dib f9 fw4 lh-solid v-top"
|
||||
style={{ width: 'max-content' }}>
|
||||
<Text
|
||||
display='inline-block'
|
||||
fontSize='0'
|
||||
verticalAlign='top'
|
||||
width='max-content'>
|
||||
{title}
|
||||
</h2>
|
||||
</Text>
|
||||
</Link>
|
||||
<TabBar
|
||||
location={props.location}
|
||||
popout={props.popout}
|
||||
popoutHref={`/~link/popout/${props.resourcePath}/settings`}
|
||||
settings={`/~link/${props.resourcePath}/settings`}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-100 pl3 mt4 cf">
|
||||
<h2 className="f8 pb2">Collection Settings</h2>
|
||||
</Row>
|
||||
<Box width='100' pl='3' mt='3'>
|
||||
<Text display='block' fontSize='1' pb='2'>Collection Settings</Text>
|
||||
{this.renderRemove()}
|
||||
{this.renderDelete()}
|
||||
<MetadataSettings
|
||||
@ -176,8 +177,8 @@ export class SettingsScreen extends Component {
|
||||
classes="absolute right-1 bottom-1 pa2 ba b--black b--gray0-d white-d"
|
||||
text={this.state.type}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,24 +6,16 @@ export class Skeleton extends Component {
|
||||
render() {
|
||||
const { props } = this;
|
||||
const rightPanelHide = props.rightPanelHide ? 'dn-s' : '';
|
||||
const popout = props.popout ? props.popout : false;
|
||||
|
||||
const popoutWindow = (popout)
|
||||
? '' : 'ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl';
|
||||
|
||||
const popoutBorder = (popout)
|
||||
? '' : 'ba-m ba-l ba-xl b--gray4 b--gray1-d br1';
|
||||
|
||||
const linkInvites = ('/link' in props.invites)
|
||||
? props.invites['/link'] : {};
|
||||
|
||||
return (
|
||||
<div className={'absolute w-100 ' + popoutWindow}
|
||||
<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 ' + popoutBorder}>
|
||||
<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}
|
||||
popout={popout}
|
||||
associations={props.associations}
|
||||
invites={linkInvites}
|
||||
groups={props.groups}
|
||||
|
@ -84,7 +84,6 @@ export default function PublishApp(props: PublishAppProps) {
|
||||
]}
|
||||
>
|
||||
<RouterSkeleton
|
||||
popout={location.pathname.includes("popout/")}
|
||||
active={active}
|
||||
sidebarShown={sidebarShown}
|
||||
invites={invites}
|
||||
|
@ -37,7 +37,6 @@ export function NotePreview(props: NotePreviewProps) {
|
||||
comment = `${note["num-comments"]} Comments`;
|
||||
}
|
||||
const date = moment(note["date-created"]).fromNow();
|
||||
//const popout = props.popout ? "popout/" : "";
|
||||
const url = `${props.book}/note/${note["note-id"]}`;
|
||||
|
||||
return (
|
||||
|
@ -1,9 +1,11 @@
|
||||
import React from "react";
|
||||
import RemoteContent from "~/views/components/RemoteContent";
|
||||
import React from 'react';
|
||||
import RemoteContent from '~/views/components/RemoteContent';
|
||||
import { hasProvider } from 'oembed-parser';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import RemarkDisableTokenizers from 'remark-disable-tokenizers';
|
||||
|
||||
import { BaseAnchor, Text } from '@tlon/indigo-react';
|
||||
|
||||
const DISABLED_BLOCK_TOKENS = [
|
||||
'indentedCode',
|
||||
'atxHeading',
|
||||
@ -17,24 +19,27 @@ const DISABLED_BLOCK_TOKENS = [
|
||||
|
||||
const DISABLED_INLINE_TOKENS = [];
|
||||
|
||||
const RichText = React.memo(({remoteContentPolicy, ...props}) => (
|
||||
const RichText = React.memo(({ remoteContentPolicy, ...props }) => (
|
||||
<ReactMarkdown
|
||||
{...props}
|
||||
renderers={{
|
||||
link: (props) => {
|
||||
if (hasProvider(props.href)) {
|
||||
return <RemoteContent className="mw-100" url={props.href} remoteContentPolicy={remoteContentPolicy}/>;
|
||||
return <RemoteContent className="mw-100" url={props.href} remoteContentPolicy={remoteContentPolicy} />;
|
||||
}
|
||||
return <a {...props} className="bb b--white-d b--black">{props.children}</a>
|
||||
return <BaseAnchor target='_blank' rel='noreferrer noopener' borderBottom='1px solid' {...props}>{props.children}</BaseAnchor>;
|
||||
},
|
||||
paragraph: (props) => {
|
||||
return <p {...props} className="mb2 lh-copy">{props.children}</p>
|
||||
return <Text display='block' mb='2' {...props}>{props.children}</Text>;
|
||||
}
|
||||
}}
|
||||
plugins={[[
|
||||
RemarkDisableTokenizers,
|
||||
{ block: DISABLED_BLOCK_TOKENS, inline: DISABLED_INLINE_TOKENS }
|
||||
]]} />
|
||||
]]}
|
||||
/>
|
||||
));
|
||||
|
||||
export default RichText;
|
||||
RichText.displayName = 'RichText';
|
||||
|
||||
export default RichText;
|
||||
|
@ -2,9 +2,6 @@ import React, { Component } from 'react';
|
||||
|
||||
export class SidebarSwitcher extends Component {
|
||||
render() {
|
||||
const popoutSwitcher = this.props.popout
|
||||
? ' dn-m dn-l dn-xl'
|
||||
: ' dib-m dib-l dib-xl';
|
||||
|
||||
const classes = this.props.classes ? this.props.classes : '';
|
||||
|
||||
@ -21,7 +18,7 @@ export class SidebarSwitcher extends Component {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
className={'pr3 dn ' + popoutSwitcher}
|
||||
className='pr3 dn dib-m dib-l dib-xl'
|
||||
src={
|
||||
this.props.sidebarShown
|
||||
? '/~landscape/img/ChatSwitcherLink.png'
|
||||
|
@ -12,9 +12,6 @@ const StatusBar = (props) => {
|
||||
const location = useLocation();
|
||||
const atHome = Boolean(location.pathname === '/');
|
||||
|
||||
const display = (!window.location.href.includes('popout/'))
|
||||
? 'grid' : 'none';
|
||||
|
||||
const invites = (props.invites && props.invites['/contacts'])
|
||||
? props.invites['/contacts']
|
||||
: {};
|
||||
@ -24,7 +21,7 @@ const StatusBar = (props) => {
|
||||
|
||||
return (
|
||||
<Box
|
||||
display={display}
|
||||
display='grid'
|
||||
width="100%"
|
||||
gridTemplateRows="30px"
|
||||
gridTemplateColumns="3fr 1fr"
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
|
||||
export const TabBar = (props) => {
|
||||
const {
|
||||
location,
|
||||
settings,
|
||||
popoutHref
|
||||
} = props;
|
||||
let setColor = '', popout = '';
|
||||
let setColor = '';
|
||||
|
||||
if (location.pathname.includes('/settings')) {
|
||||
setColor = 'black white-d';
|
||||
@ -15,28 +16,15 @@ export const TabBar = (props) => {
|
||||
setColor = 'gray3';
|
||||
}
|
||||
|
||||
const hidePopoutIcon = (popout)
|
||||
? 'dn-m dn-l dn-xl' : 'dib-m dib-l dib-xl';
|
||||
|
||||
return (
|
||||
<div className="dib flex-shrink-0 flex-grow-1">
|
||||
<div className={'dib pt2 f9 pl6 pr6 lh-solid'}>
|
||||
<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>
|
||||
</div>
|
||||
<a href={popoutHref} rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="dib fr pr1"
|
||||
style={{ paddingTop: '8px' }}>
|
||||
<img
|
||||
className={'flex-shrink-0 pr3 dn ' + hidePopoutIcon}
|
||||
src="/~chat/img/popout.png"
|
||||
height="16"
|
||||
width="16" />
|
||||
</a>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { BaseInput } from '@tlon/indigo-react';
|
||||
|
||||
export class OmniboxInput extends Component {
|
||||
render() {
|
||||
const { props } = this;
|
||||
return (
|
||||
<input
|
||||
<BaseInput
|
||||
ref={(el) => {
|
||||
this.input = el;
|
||||
if (el && document.activeElement.isSameNode(el)) {
|
||||
@ -14,8 +15,15 @@ export class OmniboxInput extends Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
className='ba b--transparent w-100 br2 white-d bg-gray0-d inter f9 pa2'
|
||||
style={{ maxWidth: 'calc(600px - 1.15rem)', boxSizing: 'border-box' }}
|
||||
width='100%'
|
||||
p='2'
|
||||
backgroundColor='white'
|
||||
color='black'
|
||||
border='1px solid transparent'
|
||||
borderRadius='2'
|
||||
maxWidth='calc(600px - 1.15rem)'
|
||||
fontSize='0'
|
||||
style={{ boxSizing: 'border-box' }}
|
||||
placeholder='Search...'
|
||||
onKeyDown={props.control}
|
||||
onChange={props.search}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Box, Text, Row, BaseInput } from '@tlon/indigo-react';
|
||||
|
||||
export class MetadataColor extends Component {
|
||||
constructor(props) {
|
||||
@ -39,29 +40,46 @@ export class MetadataColor extends Component {
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
return (
|
||||
<div className={'cf w-100 mb3 ' + ((props.isDisabled) ? 'o-30' : '')}>
|
||||
<p className="f8 lh-copy">Change color</p>
|
||||
<p className="f9 gray2 db mb4">Give this {props.resource} a color when viewing group channels</p>
|
||||
<div className="relative w-100 flex"
|
||||
style={{ maxWidth: '10rem' }}
|
||||
<Box
|
||||
width='100%'
|
||||
mb='3'
|
||||
opacity={(props.isDisabled) ? '0.3' : '1'}
|
||||
>
|
||||
<Text my='1' display='block' fontSize='1'>Change color</Text>
|
||||
<Text fontSize='0' gray display='block' mb='3'>Give this {props.resource} a color when viewing group channels</Text>
|
||||
<Row
|
||||
position='relative'
|
||||
maxWidth='10rem'
|
||||
width='100%'
|
||||
>
|
||||
<div className="absolute"
|
||||
style={{
|
||||
height: 16,
|
||||
width: 16,
|
||||
backgroundColor: state.color,
|
||||
top: 13,
|
||||
left: 11
|
||||
}} />
|
||||
<input
|
||||
className={'pl7 f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
||||
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
||||
value={state.color}
|
||||
disabled={props.isDisabled}
|
||||
onChange={this.changeColor}
|
||||
onBlur={this.submitColor} />
|
||||
</div>
|
||||
</div>
|
||||
<Box
|
||||
position='absolute'
|
||||
height='16px'
|
||||
width='16px'
|
||||
backgroundColor={state.color}
|
||||
style={{ top: 18, left: 11 }}
|
||||
/>
|
||||
<BaseInput
|
||||
pl='5'
|
||||
fontSize='1'
|
||||
border='1px solid'
|
||||
borderColor='gray'
|
||||
backgroundColor='white'
|
||||
pt='3'
|
||||
pb='3'
|
||||
pr='3'
|
||||
display='block'
|
||||
width='100%'
|
||||
flex='auto'
|
||||
color='black'
|
||||
mr='3'
|
||||
value={state.color}
|
||||
disabled={props.isDisabled}
|
||||
onChange={this.changeColor}
|
||||
onBlur={this.submitColor}
|
||||
/>
|
||||
</Row>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Box, Text, Row, BaseInput } from '@tlon/indigo-react';
|
||||
|
||||
export class MetadataInput extends Component {
|
||||
|
||||
@ -26,13 +27,29 @@ export class MetadataInput extends Component {
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={'w-100 mb3 fl ' + ((isDisabled) ? 'o-30' : '')}>
|
||||
<p className="f8 lh-copy">{title}</p>
|
||||
<p className="f9 gray2 db mb4">{description}</p>
|
||||
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
||||
<input
|
||||
className={'f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
||||
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
||||
<Box
|
||||
width='100%'
|
||||
mb='3'
|
||||
opacity={(isDisabled) ? '0.3' : '1'}
|
||||
>
|
||||
<Text display='block' fontSize='1' mb='1'>{title}</Text>
|
||||
<Text display='block' mb='4' fontSize='0' gray>{description}</Text>
|
||||
<Row
|
||||
width='100%'
|
||||
position='relative'
|
||||
maxWidth='29rem'
|
||||
>
|
||||
<BaseInput
|
||||
fontSize='1'
|
||||
border='1px solid'
|
||||
borderColor='gray'
|
||||
backgroundColor='white'
|
||||
p='3'
|
||||
display='block'
|
||||
color='black'
|
||||
width='100'
|
||||
flex='auto'
|
||||
mr='3'
|
||||
type="text"
|
||||
value={this.state.value}
|
||||
disabled={isDisabled}
|
||||
@ -45,8 +62,8 @@ export class MetadataInput extends Component {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
|
||||
import { MetadataColor } from './color';
|
||||
import { MetadataInput } from './input';
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
import { uxToHex } from '~/logic/lib/util';
|
||||
|
||||
|
||||
@ -27,7 +28,7 @@ export const MetadataSettings = (props) => {
|
||||
`#${uxToHex(props.association.metadata.color)}` : '';
|
||||
|
||||
return (
|
||||
<div className="cf mt6">
|
||||
<Box mt='6'>
|
||||
<MetadataInput
|
||||
title='Rename'
|
||||
description={`Change the name of this ${resource}`}
|
||||
@ -90,7 +91,7 @@ export const MetadataSettings = (props) => {
|
||||
});
|
||||
});
|
||||
}} />
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user