Merge pull request #4760 from urbit/mp/landscape/omnibus

landscape: assigned omnibus
This commit is contained in:
matildepark 2021-04-13 23:53:08 -04:00 committed by GitHub
commit 9c6658d034
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 137 additions and 102 deletions

View File

@ -98,8 +98,15 @@ h2 {
font-family: 'Inter', sans-serif;
}
.embed-container:not(.embed-container .embed-container):not(.links) {
padding: 0px 8px 8px 8px;
}
.embed-container iframe {
max-width: 100%;
width: 100%;
height: 100%;
margin-top: 8px;
}
.mh-16 {

View File

@ -134,7 +134,13 @@ export function ProfileActions(props: any): ReactElement {
history.push(`/~profile/${ship}/edit`);
}}
>
Edit {isPublic ? 'Public' : 'Private'} Profile
Edit
<Text
fontWeight='500'
cursor='pointer'
display={['none','inline']}>
{isPublic ? ' Public' : ' Private'} Profile
</Text>
</Text>
<SetStatusBarModal
isControl
@ -183,7 +189,7 @@ export function Profile(props: any): ReactElement | null {
}
return (
<Center p={[0, 4]} height='100%' width='100%'>
<Center p={[3, 4]} height='100%' width='100%'>
<Box maxWidth='600px' width='100%' position='relative'>
{ isEdit ? (
<EditProfile

View File

@ -49,20 +49,20 @@
font-family: 'Source Code Pro';
}
.publish .CodeMirror-selected { background:#BAE3FE !important; color: black; }
.publish .CodeMirror-selected { background:#BAE3FE !important; color: inherit; }
.publish .cm-s-tlon span { font-family: "Source Code Pro"}
.publish .cm-s-tlon span.cm-meta { color: var(--gray); }
.publish .cm-s-tlon span.cm-number { color: var(--gray); }
.publish .cm-s-tlon span.cm-keyword { line-height: 1em; font-weight: bold; color: var(--gray); }
.publish .cm-s-tlon span.cm-atom { font-weight: bold; color: var(--gray); }
.publish .cm-s-tlon span.cm-def { color: black; }
.publish .cm-s-tlon span.cm-variable { color: black; }
.publish .cm-s-tlon span.cm-variable-2 { color: black; }
.publish .cm-s-tlon span.cm-variable-3, .publish .cm-s-tlon span.cm-type { color: black; }
.publish .cm-s-tlon span.cm-property { color: black; }
.publish .cm-s-tlon span.cm-operator { color: black; }
.publish .cm-s-tlon span.cm-comment { color: black; background-color: var(--light-gray); display: inline-block; border-radius: 2px;}
.publish .cm-s-tlon span.cm-def { color: inherit; }
.publish .cm-s-tlon span.cm-variable { color: inherit; }
.publish .cm-s-tlon span.cm-variable-2 { color: inherit; }
.publish .cm-s-tlon span.cm-variable-3, .publish .cm-s-tlon span.cm-type { color: inherit; }
.publish .cm-s-tlon span.cm-property { color: inherit; }
.publish .cm-s-tlon span.cm-operator { color: inherit; }
.publish .cm-s-tlon span.cm-comment { color: inherit; background-color: var(--light-gray); display: inline-block; border-radius: 2px;}
.publish .cm-s-tlon span.cm-string { color: var(--dark-gray); }
.publish .cm-s-tlon span.cm-string-2 { color: var(--gray); }
.publish .cm-s-tlon span.cm-qualifier { color: #555; }

View File

@ -83,7 +83,7 @@ export default function S3Form(props: S3FormProps): ReactElement {
style={{ textDecoration: 'none' }}
borderBottom='1'
ml='1'
href='https://urbit.org/using/operations/using-your-ship/#bucket-setup'
href='https://urbit.org/using/os/s3/'
>
Learn more
</Anchor>

View File

@ -9,12 +9,12 @@ import { Group } from '@urbit/api';
import { uxToHex, cite, useShowNickname, deSig } from '~/logic/lib/util';
import useSettingsState, {selectCalmState} from "~/logic/state/settings";
import useLocalState from "~/logic/state/local";
import OverlaySigil from './OverlaySigil';
import { Sigil } from '~/logic/lib/sigil';
import Timestamp from './Timestamp';
import useContactState from '~/logic/state/contact';
import { useCopy } from '~/logic/lib/useCopy';
import ProfileOverlay from './ProfileOverlay';
import {PropFunc} from '~/types';
import { PropFunc } from '~/types';
interface AuthorProps {
ship: string;
@ -61,6 +61,7 @@ export default function Author(props: AuthorProps & PropFunc<typeof Box>): React
const { hideAvatars } = useSettingsState(selectCalmState);
const name = showNickname && contact ? contact.nickname : cite(ship);
const stamp = moment(date);
const { copyDisplay, doCopy, didCopy } = useCopy(`~${ship}`, name);
const [showOverlay, setShowOverlay] = useState(false);
@ -108,11 +109,13 @@ export default function Author(props: AuthorProps & PropFunc<typeof Box>): React
ml={showImage ? 2 : 0}
color='black'
fontSize='1'
cursor='pointer'
lineHeight='tall'
fontFamily={showNickname ? 'sans' : 'mono'}
fontWeight={showNickname ? '500' : '400'}
onClick={doCopy}
>
{name}
{copyDisplay}
</Box>
{ !dontShowTime && (
<Timestamp

View File

@ -96,7 +96,7 @@ export function CommentItem(props: CommentItemProps): ReactElement {
unread={props.unread}
group={group}
>
<Row px="2" gapX="2" alignItems="center">
<Row px="2" gapX="2" height="18px">
<Action bg="white" onClick={doCopy}>{copyDisplay}</Action>
{adminLinks}
</Row>

View File

@ -6,9 +6,7 @@ import EmbedContainer from 'react-oembed-container';
import useSettingsState from '~/logic/state/settings';
import { RemoteContentPolicy } from '~/types/local-update';
import { VirtualContextProps, withVirtual } from "~/logic/lib/virtualContext";
import { IS_IOS } from '~/logic/lib/platform';
import withState from '~/logic/lib/withState';
import {Link} from 'react-router-dom';
type RemoteContentProps = VirtualContextProps & {
url: string;
@ -130,33 +128,41 @@ return;
});
}
wrapInLink(contents, textOnly = false) {
wrapInLink(contents, textOnly = false, unfold = false, unfoldEmbed = null, embedContainer = null) {
const { style } = this.props;
return (
<Box borderRadius="1" backgroundColor="washedGray" maxWidth="min(100%, 20rem)">
<Row
alignItems="center"
maxWidth="min(100%, 20rem)"
gapX="1" borderRadius="1" backgroundColor="washedGray">
gapX="1">
{ textOnly && (<Icon ml="2" display="block" icon="ArrowExternal" />)}
{ !textOnly && unfoldEmbed && (
<Icon
ml='2'
display='block'
onClick={unfoldEmbed}
icon={unfold ? 'TriangleSouth' : 'TriangleEast'}/>
)}
<BaseAnchor
display="flex"
p="2"
onClick={(e) => { e.stopPropagation(); }}
href={this.props.url}
flexShrink={0}
whiteSpace="nowrap"
overflow="hidden"
textOverflow="ellipsis"
minWidth="0"
width={textOnly ? "calc(100% - 24px)" : "fit-content"}
maxWidth="min(500px, 100%)"
style={{ color: 'inherit', textDecoration: 'none', ...style }}
target="_blank"
rel="noopener noreferrer"
onClick={(e) => { e.stopPropagation(); }}
href={this.props.url}
whiteSpace="nowrap"
overflow="hidden"
textOverflow="ellipsis"
minWidth="0"
width={textOnly ? "calc(100% - 24px)" : "fit-content"}
maxWidth="min(500px, 100%)"
style={{ color: 'inherit', textDecoration: 'none', ...style }}
target="_blank"
rel="noopener noreferrer"
>
{contents}
</BaseAnchor>
</Row>
{embedContainer}
</Box>
);
}
@ -170,7 +176,6 @@ return;
remoteContentPolicy,
url,
text,
unfold = false,
renderUrl = true,
imageProps = {},
audioProps = {},
@ -208,68 +213,58 @@ return;
return (
<>
{renderUrl
? this.wrapInLink(<TruncatedText {...textProps}>{text || url}</TruncatedText>)
? this.wrapInLink(
<TruncatedText {...textProps}>{url}</TruncatedText>,
false,
this.state.unfold,
this.unfoldEmbed,
<audio
onClick={(e) => { e.stopPropagation(); }}
controls
className={this.state.unfold ? "db" : "dn"}
src={url}
style={style}
onLoad={onLoad}
objectFit="contain"
height="100%"
width="100%"
{...audioProps}
{...props}
/>)
: null}
<audio
onClick={(e) => { e.stopPropagation(); }}
controls
className="db"
src={url}
style={style}
onLoad={onLoad}
objectFit="contain"
height="100%"
width="100%"
{...audioProps}
{...props}
/>
</>
);
} else if (isVideo && remoteContentPolicy.videoShown) {
return (
<>
{renderUrl
? this.wrapInLink(<TruncatedText {...textProps}>{text || url}</TruncatedText>)
? this.wrapInLink(
<TruncatedText {...textProps}>{url}</TruncatedText>,
false,
this.state.unfold,
this.unfoldEmbed,
<video
onClick={(e) => { e.stopPropagation(); }}
controls
className={this.state.unfold ? 'db' : 'dn pa2'}
src={url}
style={style}
onLoad={onLoad}
objectFit="contain"
height="100%"
width="100%"
{...videoProps}
{...props}
/>)
: null}
<video
onClick={(e) => { e.stopPropagation(); }}
controls
className="db"
src={url}
style={style}
onLoad={onLoad}
objectFit="contain"
height="100%"
width="100%"
{...videoProps}
{...props}
/>
</>
);
} else if (isOembed && remoteContentPolicy.oembedShown) {
if (!this.state.embed || this.state.embed?.html === '') {
this.loadOembed();
}
return (
<Fragment>
{renderUrl
? this.wrapInLink(<TruncatedText {...textProps}>{(this.state.embed && this.state.embed.title)
? this.state.embed.title
: (text || url)}</TruncatedText>, true)
: null}
{this.state.embed !== 'error' && this.state.embed?.html && !unfold ? <Button
display='inline-flex'
border={1}
height={3}
ml={1}
onClick={this.unfoldEmbed}
flexShrink={0}
style={{ cursor: 'pointer' }}
>
{this.state.unfold ? 'collapse' : 'expand'}
</Button> : null}
<Box
const renderEmbed = !(this.state.embed !== 'error' && this.state.embed?.html);
const embed = <Box
mb='2'
width='100%'
flexShrink={0}
@ -281,17 +276,33 @@ return;
{...oembedProps}
{...props}
>
{this.state.embed && this.state.embed.html && this.state.unfold
? <EmbedContainer markup={this.state.embed.html}>
<div className="embed-container" ref={(el) => {
this.onLoad();
this.containerRef = el;
}}
dangerouslySetInnerHTML={{ __html: this.state.embed.html }}
></div>
</EmbedContainer>
: null}
</Box>
<TruncatedText
display={(renderUrl && this.state.embed?.title && this.state.embed.title !== url) ? 'inline-block' : 'none'}
fontWeight='bold' width='100%'>
{this.state.embed?.title}
</TruncatedText>
{this.state.embed && this.state.embed.html && this.state.unfold
? <EmbedContainer markup={this.state.embed.html}>
<div className="embed-container" ref={(el) => {
this.onLoad();
this.containerRef = el;
}}
dangerouslySetInnerHTML={{ __html: this.state.embed.html }}
></div>
</EmbedContainer>
: null}
</Box>;
return (
<Fragment>
{renderUrl
? this.wrapInLink(
<TruncatedText {...textProps}>{url}</TruncatedText>,
renderEmbed,
this.state.unfold,
this.unfoldEmbed,
embed
) : embed}
</Fragment>
);
} else {

View File

@ -3,7 +3,7 @@ import { Link } from 'react-router-dom';
import ReactMarkdown from 'react-markdown';
import RemarkDisableTokenizers from 'remark-disable-tokenizers';
import urbitOb from 'urbit-ob';
import { Text } from '@tlon/indigo-react';
import { Text, Anchor } from '@tlon/indigo-react';
import { GroupLink } from '~/views/components/GroupLink';
import { Row } from '@tlon/indigo-react';
@ -22,7 +22,6 @@ const DISABLED_INLINE_TOKENS = [
'autoLink',
'url',
'email',
'link',
'reference'
];
@ -75,6 +74,9 @@ const renderers = {
{value}
</Text>
);
},
link: (props) => {
return <Anchor src={props.href} borderBottom="1" color="black">{props.children}</Anchor>
}
};

View File

@ -81,6 +81,9 @@ export function JoinGroup(props: JoinGroupProps): ReactElement {
if(group === TUTORIAL_GROUP_RESOURCE) {
await api.settings.putEntry('tutorial', 'joined', Date.now());
}
if (group in groups) {
return history.push(`/~landscape${group}`);
}
await api.groups.join(ship, name);
try {
await waiter((p) => {
@ -111,6 +114,9 @@ export function JoinGroup(props: JoinGroupProps): ReactElement {
async (values: FormSchema, actions: FormikHelpers<FormSchema>) => {
const [ship, name] = values.group.split('/');
const path = `/ship/${ship}/${name}`;
if (path in groups) {
return history.push(`/~landscape${path}`);
}
// skip if it's unmanaged
try {
const prev = await api.metadata.preview(path);

View File

@ -295,7 +295,7 @@ function Participant(props: {
const resource = resourceFromPath(association.group);
if(contact.pending) {
await api.groups.changePolicy(
resource,
resource,
{ invite: { removeInvites: [`~${contact.patp}`] } }
);
} else {
@ -305,12 +305,12 @@ function Participant(props: {
const avatar =
contact?.avatar !== null && !hideAvatars ? (
<Image
src={contact.avatar}
height={32}
width={32}
<Image
src={contact.avatar}
height={32}
width={32}
display='inline-block'
style={{ objectFit: 'cover' }}
style={{ objectFit: 'cover' }}
/>
) : (
<Sigil ship={contact.patp} size={32} color={`#${color}`} />
@ -386,9 +386,9 @@ function Participant(props: {
{(contact.patp !== window.ship) && (<StatelessAsyncAction onClick={onKick} bg="transparent">
<Text color="red">Kick from {title}</Text>
</StatelessAsyncAction>)}
<StatelessAsyncAction onClick={onPromote} bg="transparent">
{!contact.pending && <StatelessAsyncAction onClick={onPromote} bg="transparent">
Promote to Admin
</StatelessAsyncAction>
</StatelessAsyncAction>}
</>
)}
</>