mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-09-21 15:38:59 +03:00
Merge pull request #4760 from urbit/mp/landscape/omnibus
landscape: assigned omnibus
This commit is contained in:
commit
9c6658d034
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
Loading…
Reference in New Issue
Block a user