mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-25 07:52:59 +03:00
Merge pull request #5228 from urbit/hm/landscape-app-link
interface: app permalink embeds
This commit is contained in:
commit
37b1e9569b
@ -330,7 +330,7 @@
|
||||
=/ body=json (need (de-json:html q.u.body.request.inbound-request))
|
||||
=/ input=vase (slop !>(~) (tube !>(body)))
|
||||
=/ boc bec
|
||||
=/ =start-args [~ `tid boc(q desk) thread input]
|
||||
=/ =start-args [~ `tid boc(q desk, r da+now.bowl) thread input]
|
||||
(handle-start-thread start-args)
|
||||
::
|
||||
++ on-poke-input
|
||||
|
@ -48,7 +48,7 @@
|
||||
=+ !<(=diff:hood q.cage.sign)
|
||||
?+ -.diff `this
|
||||
::
|
||||
%merge
|
||||
%commit
|
||||
=/ =action:hark ~(updated de:cc desk.diff)
|
||||
:_ this
|
||||
~[(poke:ha:cc action)]
|
||||
|
@ -2,6 +2,8 @@
|
||||
import {
|
||||
ReferenceContent, resourceFromPath
|
||||
} from '@urbit/api';
|
||||
import { isValidPatp } from 'urbit-ob';
|
||||
import _ from 'lodash';
|
||||
|
||||
export function getPermalinkForGraph(
|
||||
group: string,
|
||||
@ -18,7 +20,15 @@ function getPermalinkForAssociatedGroup(group: string) {
|
||||
return `web+urbitgraph://group/${ship}/${name}`;
|
||||
}
|
||||
|
||||
type Permalink = GraphPermalink | GroupPermalink;
|
||||
type Permalink = AppPermalink | GraphPermalink | GroupPermalink;
|
||||
|
||||
export interface AppPermalink {
|
||||
type: 'app';
|
||||
link: string;
|
||||
ship: string;
|
||||
desk: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface GroupPermalink {
|
||||
type: 'group';
|
||||
@ -54,20 +64,13 @@ function parseGraphPermalink(
|
||||
}
|
||||
|
||||
export function permalinkToReference(link: Permalink): ReferenceContent {
|
||||
if(link.type === 'graph') {
|
||||
const reference = {
|
||||
graph: {
|
||||
graph: link.graph,
|
||||
group: link.group,
|
||||
index: link.index
|
||||
}
|
||||
};
|
||||
return { reference };
|
||||
} else {
|
||||
const reference = {
|
||||
group: link.group
|
||||
};
|
||||
return { reference };
|
||||
switch (link.type) {
|
||||
case 'graph':
|
||||
return { reference: { graph: _.omit(link, ['type', 'link']) } };
|
||||
case 'group':
|
||||
return { reference: { group: link.group } };
|
||||
case 'app':
|
||||
return { reference: { app: _.omit(link, ['type', 'link']) } };
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +83,15 @@ export function referenceToPermalink({ reference }: ReferenceContent): Permalink
|
||||
link,
|
||||
...reference.graph
|
||||
};
|
||||
} else if ('app' in reference) {
|
||||
const { ship, desk, path } = reference.app;
|
||||
return {
|
||||
type: 'app',
|
||||
link: `web+urbitgraph://${ship}/${desk}${path}`,
|
||||
ship,
|
||||
desk,
|
||||
path
|
||||
};
|
||||
} else {
|
||||
const link = `web+urbitgraph://group${reference.group.slice(5)}`;
|
||||
return {
|
||||
@ -92,6 +104,7 @@ export function referenceToPermalink({ reference }: ReferenceContent): Permalink
|
||||
|
||||
export function parsePermalink(url: string): Permalink | null {
|
||||
const [kind, ...rest] = url.slice(17).split('/');
|
||||
|
||||
if (kind === 'group') {
|
||||
const [ship, name, ...graph] = rest;
|
||||
const group = `/ship/${ship}/${name}`;
|
||||
@ -104,5 +117,18 @@ export function parsePermalink(url: string): Permalink | null {
|
||||
link: url.slice(11)
|
||||
};
|
||||
}
|
||||
|
||||
if (isValidPatp(kind)) {
|
||||
const [desk, ...parts] = rest;
|
||||
const path = '/' + parts.join('/');
|
||||
return {
|
||||
type: 'app',
|
||||
link: url,
|
||||
ship: kind,
|
||||
desk,
|
||||
path
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
54
pkg/interface/src/logic/state/docket.ts
Normal file
54
pkg/interface/src/logic/state/docket.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { Docket, Treaties, Treaty } from '@urbit/api';
|
||||
import { useCallback } from 'react';
|
||||
import create from 'zustand';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
interface DocketState {
|
||||
treaties: Treaties;
|
||||
requestTreaty: (ship: string, desk: string) => Promise<Treaty>;
|
||||
}
|
||||
|
||||
const useDocketState = create<DocketState>((set, get) => ({
|
||||
requestTreaty: async (ship: string, desk: string) => {
|
||||
const { treaties } = get();
|
||||
const key = `${ship}/${desk}`;
|
||||
if (key in treaties) {
|
||||
return treaties[key];
|
||||
}
|
||||
|
||||
const result = await airlock.subscribeOnce('treaty', `/treaty/${key}`, 20000);
|
||||
const treaty = { ...normalizeDocket(result, desk), ship };
|
||||
set(state => ({
|
||||
treaties: { ...state.treaties, [key]: treaty }
|
||||
}));
|
||||
return treaty;
|
||||
},
|
||||
treaties: {},
|
||||
set
|
||||
}));
|
||||
|
||||
function normalizeDocket<T extends Docket>(docket: T, desk: string): T {
|
||||
const color = docket?.color?.startsWith('#')
|
||||
? docket.color
|
||||
: `#${docket.color.slice(2).replace('.', '')}`.toUpperCase();
|
||||
|
||||
return {
|
||||
...docket,
|
||||
desk,
|
||||
color
|
||||
};
|
||||
}
|
||||
|
||||
export function useTreaty(host: string, desk: string) {
|
||||
return useDocketState(
|
||||
useCallback(
|
||||
(s) => {
|
||||
const ref = `${host}/${desk}`;
|
||||
return s.treaties[ref];
|
||||
},
|
||||
[host, desk]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default useDocketState;
|
@ -1,10 +1,11 @@
|
||||
import { BaseAnchor, Box, Center, Col, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import { BaseAnchor, Box, Button, Center, Col, H3, Icon, Image, Row, Text } from '@tlon/indigo-react';
|
||||
import { Association, GraphNode, resourceFromPath, GraphConfig } from '@urbit/api';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
getPermalinkForGraph, GraphPermalink as IGraphPermalink, parsePermalink
|
||||
getPermalinkForGraph, GraphPermalink as IGraphPermalink, parsePermalink,
|
||||
AppPermalink as IAppPermalink
|
||||
} from '~/logic/lib/permalinks';
|
||||
import { getModuleIcon, GraphModule } from '~/logic/lib/util';
|
||||
import { useVirtualResizeProp } from '~/logic/lib/virtualContext';
|
||||
@ -12,6 +13,9 @@ import useGraphState from '~/logic/state/graph';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import { GroupLink } from '~/views/components/GroupLink';
|
||||
import { TranscludedNode } from './TranscludedNode';
|
||||
import styled from 'styled-components';
|
||||
import Author from '~/views/components/Author';
|
||||
import useDocketState, { useTreaty } from '~/logic/state/docket';
|
||||
|
||||
function Placeholder(type) {
|
||||
const lines = (type) => {
|
||||
@ -184,6 +188,61 @@ function GraphPermalink(
|
||||
);
|
||||
}
|
||||
|
||||
const ClampedText = styled(Text)`
|
||||
display: -webkit-box;
|
||||
line-clamp: 2;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
function AppPermalink({ link, ship, desk }: Omit<IAppPermalink, 'type'>) {
|
||||
const treaty = useTreaty(ship, desk);
|
||||
|
||||
useEffect(() => {
|
||||
if (!treaty) {
|
||||
useDocketState.getState().requestTreaty(ship, desk);
|
||||
}
|
||||
}, [treaty, ship, desk]);
|
||||
|
||||
return (
|
||||
<Row
|
||||
display="inline-flex"
|
||||
width="500px"
|
||||
padding={3}
|
||||
bg="washedGray"
|
||||
borderRadius={3}
|
||||
>
|
||||
<Box
|
||||
position="relative"
|
||||
flex="none"
|
||||
height="132px"
|
||||
width="132px"
|
||||
marginRight={3}
|
||||
borderRadius={3}
|
||||
bg={treaty?.color || 'gray'}
|
||||
>
|
||||
{treaty?.image && (
|
||||
<Image
|
||||
src={treaty.image}
|
||||
position="absolute"
|
||||
top="0"
|
||||
left="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Col>
|
||||
<H3 color="black">{treaty?.title}</H3>
|
||||
{treaty?.ship && <Author ship={treaty?.ship} showImage dontShowTime={true} marginBottom={2} />}
|
||||
<ClampedText marginBottom={2} color="gray">{treaty?.info}</ClampedText>
|
||||
<Button as="a" href={link} primary alignSelf="start" display="inline-flex" marginTop="auto">Open App</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
function PermalinkDetails(props: {
|
||||
title: string;
|
||||
icon: any;
|
||||
@ -243,5 +302,9 @@ export function PermalinkEmbed(props: {
|
||||
showOurContact={props.showOurContact}
|
||||
/>
|
||||
);
|
||||
case 'app':
|
||||
return (
|
||||
<AppPermalink {...permalink} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ export interface AuthorProps {
|
||||
size?: number;
|
||||
lineHeight?: string | number;
|
||||
isRelativeTime?: boolean;
|
||||
dontShowTime: boolean;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
|
@ -1197,9 +1197,13 @@
|
||||
?- -.reference.content
|
||||
%graph
|
||||
txt+"[reference to msg in {~(phat tr resource.uid.reference.content)}]"
|
||||
::
|
||||
::
|
||||
%group
|
||||
txt+"[reference to msg in {~(phat tr group.reference.content)}]"
|
||||
::
|
||||
%app
|
||||
=, reference.content
|
||||
txt+"[reference to app: {(scow %p ship)}/{(trip desk)}{(spud path)}]"
|
||||
==
|
||||
::
|
||||
%mention
|
||||
|
@ -115,6 +115,7 @@
|
||||
?- -.ref
|
||||
%graph (graph +.ref)
|
||||
%group (group +.ref)
|
||||
%app (app +.ref)
|
||||
==
|
||||
::
|
||||
++ graph
|
||||
@ -128,6 +129,14 @@
|
||||
++ group
|
||||
|= grp=res
|
||||
s+(enjs-path:res grp)
|
||||
::
|
||||
++ app
|
||||
|= [=^ship =desk p=^path]
|
||||
%- pairs
|
||||
:~ ship+s+(scot %p ship)
|
||||
desk+s+desk
|
||||
path+(path p)
|
||||
==
|
||||
--
|
||||
::
|
||||
++ maybe-post
|
||||
@ -391,6 +400,7 @@
|
||||
%- of
|
||||
:~ graph+graph
|
||||
group+dejs-path:res
|
||||
app+app
|
||||
==
|
||||
::
|
||||
++ graph
|
||||
@ -399,6 +409,13 @@
|
||||
graph+dejs-path:res
|
||||
index+index
|
||||
==
|
||||
::
|
||||
++ app
|
||||
%- ot
|
||||
:~ ship+(su ;~(pfix sig fed:ag))
|
||||
desk+so
|
||||
path+pa
|
||||
==
|
||||
--
|
||||
::
|
||||
++ tang
|
||||
@ -486,6 +503,13 @@
|
||||
^- [resource update-log]
|
||||
[*resource *update-log]
|
||||
--
|
||||
++ pa
|
||||
|= j=json
|
||||
^- path
|
||||
?> ?=(%s -.j)
|
||||
?: =('/' p.j) /
|
||||
(stab p.j)
|
||||
::
|
||||
--
|
||||
::
|
||||
++ create
|
||||
|
@ -29,6 +29,7 @@
|
||||
+$ reference
|
||||
$% [%graph group=resource =uid]
|
||||
[%group group=resource]
|
||||
[%app =ship =desk =path]
|
||||
==
|
||||
::
|
||||
+$ content
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Patp } from "../lib";
|
||||
import BigIntOrderedMap from "../lib/BigIntOrderedMap";
|
||||
import BigIntArrayOrderedMap from "../lib/BigIntArrayOrderedMap";
|
||||
|
||||
import { Patp } from '../lib';
|
||||
import BigIntOrderedMap from '../lib/BigIntOrderedMap';
|
||||
import BigIntArrayOrderedMap from '../lib/BigIntArrayOrderedMap';
|
||||
|
||||
export interface TextContent {
|
||||
text: string;
|
||||
@ -17,7 +16,7 @@ export interface CodeContent {
|
||||
}
|
||||
|
||||
export interface ReferenceContent {
|
||||
reference: GraphReference | GroupReference;
|
||||
reference: AppReference | GraphReference | GroupReference;
|
||||
}
|
||||
|
||||
export interface GraphReference {
|
||||
@ -32,6 +31,14 @@ export interface GroupReference {
|
||||
group: string;
|
||||
}
|
||||
|
||||
export interface AppReference {
|
||||
app: {
|
||||
ship: string;
|
||||
desk: string;
|
||||
path: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface MentionContent {
|
||||
mention: string;
|
||||
}
|
||||
@ -49,7 +56,7 @@ export interface Post {
|
||||
index: string;
|
||||
pending?: boolean;
|
||||
signatures: string[];
|
||||
"time-sent": number;
|
||||
'time-sent': number;
|
||||
}
|
||||
|
||||
export interface GraphNodePoke {
|
||||
@ -63,7 +70,7 @@ export interface GraphChildrenPoke {
|
||||
|
||||
export interface GraphNode {
|
||||
children: Graph | null;
|
||||
post: Post;
|
||||
post: Post;
|
||||
}
|
||||
|
||||
export interface FlatGraphNode {
|
||||
|
Loading…
Reference in New Issue
Block a user