mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-09-21 07:28:30 +03:00
interface: fix iOS scrolling
This commit is contained in:
parent
7a90f04a06
commit
60cf95f3da
BIN
pkg/interface/package-lock.json
generated
BIN
pkg/interface/package-lock.json
generated
Binary file not shown.
@ -9,7 +9,7 @@
|
||||
"@reach/menu-button": "^0.10.5",
|
||||
"@reach/tabs": "^0.10.5",
|
||||
"@tlon/indigo-light": "^1.0.3",
|
||||
"@tlon/indigo-react": "^1.2.8",
|
||||
"@tlon/indigo-react": "urbit/indigo-react#lf/1.2.9",
|
||||
"@tlon/sigil-js": "^1.4.2",
|
||||
"aws-sdk": "^2.726.0",
|
||||
"classnames": "^2.2.6",
|
||||
|
33
pkg/interface/src/logic/lib/useStatelessAsyncClickable.ts
Normal file
33
pkg/interface/src/logic/lib/useStatelessAsyncClickable.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { MouseEvent, useCallback, useState, useEffect } from "react";
|
||||
export type AsyncClickableState = "waiting" | "error" | "loading" | "success";
|
||||
|
||||
export function useStatelessAsyncClickable(
|
||||
onClick: (e: MouseEvent) => Promise<void>,
|
||||
name: string
|
||||
) {
|
||||
const [state, setState] = useState<ButtonState>("waiting");
|
||||
const handleClick = useCallback(
|
||||
async (e: MouseEvent) => {
|
||||
try {
|
||||
setState("loading");
|
||||
await onClick(e);
|
||||
setState("success");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setState("error");
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
setState("waiting");
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
[onClick, setState]
|
||||
);
|
||||
|
||||
// When name changes, reset button
|
||||
useEffect(() => {
|
||||
setState("waiting");
|
||||
}, [name]);
|
||||
|
||||
return { buttonState: state, onClick: handleClick };
|
||||
}
|
@ -133,10 +133,10 @@ export default class ChatEditor extends Component {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'chat fr h-100 flex bg-gray0-d lh-copy w-100 items-center ' +
|
||||
'chat fr flex h-100 bg-gray0-d lh-copy w-100 items-center ' +
|
||||
(inCodeMode ? ' code' : '')
|
||||
}
|
||||
style={{ flexGrow: 1, paddingBottom: '3px', maxHeight: '224px', width: 'calc(100% - 88px)' }}>
|
||||
style={{ flexGrow: 1, paddingBottom: '2px', maxHeight: '224px', width: 'calc(100% - 88px)' }}>
|
||||
<CodeEditor
|
||||
value={message}
|
||||
options={options}
|
||||
|
@ -1,6 +1,7 @@
|
||||
* {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@ -8,14 +9,16 @@ html, body {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
p, h1, h2, h3, h4, h5, h6, a, input, textarea, button {
|
||||
@ -225,6 +228,7 @@ blockquote {
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
cursor: text;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.chat .CodeMirror * {
|
||||
@ -233,7 +237,6 @@ blockquote {
|
||||
|
||||
.chat .cm-s-tlon.CodeMirror {
|
||||
font-size: 16px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
@ -383,7 +386,6 @@ pre.CodeMirror-placeholder.CodeMirror-line-like { color: var(--gray); }
|
||||
|
||||
/* codemirror */
|
||||
.chat .cm-s-tlon.CodeMirror {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
margin-top: 6px;
|
||||
|
@ -33,6 +33,9 @@ button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
/* stolen from indigo-react reset.css
|
||||
* TODO: remove and add reset.css properly
|
||||
|
@ -53,7 +53,7 @@ export default function ProfileScreen(props: any) {
|
||||
return null;
|
||||
}
|
||||
if (!view && !MOBILE_BROWSER_REGEX.test(window.navigator.userAgent)) {
|
||||
history.replace("/~profile/settings");
|
||||
history.replace("/~profile/identity");
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -7,7 +7,7 @@ export function Body(
|
||||
) {
|
||||
const { children, ...boxProps } = props;
|
||||
return (
|
||||
<Box fontSize={0} px={[0, 3]} pb={[0, 3]} height="calc(100vh - 64px)" width="100%">
|
||||
<Box fontSize={0} px={[0, 3]} pb={[0, 3]} height="100%" width="100%">
|
||||
<Box
|
||||
bg="white"
|
||||
height="100%"
|
||||
|
@ -17,8 +17,8 @@ const StatusBar = (props) => {
|
||||
width="100%"
|
||||
gridTemplateRows="30px"
|
||||
gridTemplateColumns="3fr 1fr"
|
||||
py={3}
|
||||
px={3}
|
||||
py={[2,3]}
|
||||
px={[2,3]}
|
||||
>
|
||||
<Row collapse>
|
||||
<StatusBarItem mr={2} onClick={() => props.history.push('/')}>
|
||||
|
@ -94,7 +94,12 @@ export function UnjoinedResource(props: UnjoinedResourceProps) {
|
||||
<Box>
|
||||
<RichText color="gray">{description}</RichText>
|
||||
</Box>
|
||||
<StatelessAsyncButton primary width="fit-content" onClick={onJoin}>
|
||||
<StatelessAsyncButton
|
||||
name={appPath}
|
||||
primary
|
||||
width="fit-content"
|
||||
onClick={onJoin}
|
||||
>
|
||||
Join Channel
|
||||
</StatelessAsyncButton>
|
||||
</Col>
|
||||
|
@ -261,8 +261,8 @@ export class Omnibox extends Component {
|
||||
return (
|
||||
<Box
|
||||
backgroundColor='scales.black30'
|
||||
width='100vw'
|
||||
height='100vh'
|
||||
width='100%'
|
||||
height='100%'
|
||||
position='absolute'
|
||||
top='0'
|
||||
right='0'
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@ -9,8 +10,11 @@ import Profile from '~/views/apps/profile/profile';
|
||||
import ErrorComponent from '~/views/components/Error';
|
||||
|
||||
|
||||
export const Container = styled.div`
|
||||
height: calc(100% - 45px);
|
||||
export const Container = styled(Box)`
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: calc(100% - 62px);
|
||||
`;
|
||||
|
||||
|
||||
|
@ -137,7 +137,7 @@ export function GroupSwitcher(props: {
|
||||
color="gray"
|
||||
icon="Gear"
|
||||
/>
|
||||
<Text> Settings</Text>
|
||||
<Text> Group Settings</Text>
|
||||
</GroupSwitcherItem>
|
||||
<GroupSwitcherItem bottom to={navTo("/invites")}>
|
||||
<Icon
|
||||
|
@ -29,6 +29,13 @@ import { useHistory, Link } from "react-router-dom";
|
||||
import { Dropdown } from "~/views/components/Dropdown";
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
import { StatelessAsyncAction } from "~/views/components/StatelessAsyncAction";
|
||||
import styled from "styled-components";
|
||||
|
||||
const TruncText = styled(Box)`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
type Participant = Contact & { patp: string; pending: boolean };
|
||||
type ParticipantsTabId = "total" | "pending" | "admin";
|
||||
@ -108,6 +115,8 @@ export function Participants(props: {
|
||||
[props.group]
|
||||
);
|
||||
|
||||
const ourRole = roleForShip(props.group, window.ship);
|
||||
|
||||
const [filter, setFilter] = useState<ParticipantsTabId>("total");
|
||||
|
||||
const [search, _setSearch] = useState("");
|
||||
@ -137,18 +146,27 @@ export function Participants(props: {
|
||||
[search, filter, participants]
|
||||
);
|
||||
|
||||
// Sticky positioning needs to be disabled on safari due to this bug
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=210656
|
||||
// TODO: remove when resolved
|
||||
const isSafari = useMemo(() => {
|
||||
const ua = window.navigator.userAgent;
|
||||
return ua.includes("Safari") && !ua.includes("Chrome");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Col height="100%" overflowY="auto" p={2} position="relative">
|
||||
<Col height="100%" overflowY="scroll" p={2} position="relative">
|
||||
<Row
|
||||
bg="white"
|
||||
border={1}
|
||||
borderColor="washedGray"
|
||||
borderRadius={1}
|
||||
position="sticky"
|
||||
position={isSafari ? "static" : "sticky"}
|
||||
top="0px"
|
||||
mb={2}
|
||||
px={2}
|
||||
zIndex={1}
|
||||
flexShrink="0"
|
||||
>
|
||||
<Row mr="4" flexShrink="0">
|
||||
<Tab
|
||||
@ -173,20 +191,8 @@ export function Participants(props: {
|
||||
/>
|
||||
</Row>
|
||||
</Row>
|
||||
<Box
|
||||
display="grid"
|
||||
gridAutoRows={["48px 48px 1px", "48px 1px"]}
|
||||
gridTemplateColumns={["48px 1fr", "48px 1fr 144px"]}
|
||||
gridRowGap={2}
|
||||
alignItems="center"
|
||||
>
|
||||
<Row
|
||||
alignItems="center"
|
||||
gridColumn={["1 / 3", "1 / 4"]}
|
||||
bg="washedGray"
|
||||
borderRadius="1"
|
||||
px="2"
|
||||
>
|
||||
<Col flexShrink="0" width="100%" height="fit-content">
|
||||
<Row alignItems="center" bg="washedGray" borderRadius="1" px="2" my="2">
|
||||
<Icon stroke="gray" icon="MagnifyingGlass" />
|
||||
<Input
|
||||
maxWidth="256px"
|
||||
@ -198,36 +204,39 @@ export function Participants(props: {
|
||||
/>
|
||||
</Row>
|
||||
<Box
|
||||
borderBottom={1}
|
||||
borderBottomColor="washedGray"
|
||||
gridColumn={["1 / 3", "1 / 4"]}
|
||||
/>
|
||||
{filtered.map((cs, idx) => (
|
||||
<VisibilitySensor
|
||||
key={idx}
|
||||
offset={{ top: -800, bottom: -800 }}
|
||||
partialVisibility
|
||||
scrollDelay={150}
|
||||
>
|
||||
{({ isVisible }) =>
|
||||
isVisible ? (
|
||||
cs.map((c) => (
|
||||
<Participant
|
||||
api={api}
|
||||
key={c.patp}
|
||||
role="admin"
|
||||
group={props.group}
|
||||
contact={c}
|
||||
association={props.association}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<BlankParticipant length={cs.length} />
|
||||
)
|
||||
}
|
||||
</VisibilitySensor>
|
||||
))}
|
||||
</Box>
|
||||
display="grid"
|
||||
gridAutoRows={["48px 48px 1px", "48px 1px"]}
|
||||
gridTemplateColumns={["48px 1fr", "48px 2fr 1fr", "48px 3fr 1fr"]}
|
||||
gridRowGap={2}
|
||||
alignItems="center"
|
||||
>
|
||||
{filtered.map((cs, idx) => (
|
||||
<VisibilitySensor
|
||||
key={idx}
|
||||
offset={{ top: -800, bottom: -800 }}
|
||||
partialVisibility
|
||||
scrollDelay={150}
|
||||
>
|
||||
{({ isVisible }) =>
|
||||
isVisible ? (
|
||||
cs.map((c) => (
|
||||
<Participant
|
||||
api={api}
|
||||
key={c.patp}
|
||||
role={ourRole}
|
||||
group={props.group}
|
||||
contact={c}
|
||||
association={props.association}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<BlankParticipant length={cs.length} />
|
||||
)
|
||||
}
|
||||
</VisibilitySensor>
|
||||
))}
|
||||
</Box>
|
||||
</Col>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
@ -239,7 +248,6 @@ function Participant(props: {
|
||||
role?: RoleTags;
|
||||
api: GlobalApi;
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { contact, association, group, api } = props;
|
||||
const { title } = association.metadata;
|
||||
|
||||
@ -279,19 +287,22 @@ function Participant(props: {
|
||||
<Sigil ship={contact.patp} size={32} color={`#${color}`} />
|
||||
</Box>
|
||||
<Col justifyContent="center" gapY="1" height="100%">
|
||||
{contact.nickname && <Text>{contact.nickname}</Text>}
|
||||
<Text color="gray" fontFamily="mono">
|
||||
{contact.nickname && (
|
||||
<TruncText title={contact.nickname} maxWidth="85%">
|
||||
{contact.nickname}
|
||||
</TruncText>
|
||||
)}
|
||||
<Text title={contact.patp} color="gray" fontFamily="mono">
|
||||
{cite(contact.patp)}
|
||||
</Text>
|
||||
</Col>
|
||||
<Row
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
gridColumn={["1 / 3", "auto"]}
|
||||
alignItems="center"
|
||||
>
|
||||
<Col>
|
||||
<Text mb={1} color="lightGray">
|
||||
<Text color="lightGray" mb="1">
|
||||
Role
|
||||
</Text>
|
||||
<Text>{_.capitalize(role)}</Text>
|
||||
@ -334,7 +345,7 @@ function Participant(props: {
|
||||
</Col>
|
||||
}
|
||||
>
|
||||
<Icon mr={2} icon="Ellipsis" />
|
||||
<Icon display="block" icon="Ellipsis" />
|
||||
</Dropdown>
|
||||
</Row>
|
||||
<Box
|
||||
|
@ -26,7 +26,7 @@ const SidebarItem = ({ selected, icon, text, to }) => {
|
||||
py={1}
|
||||
>
|
||||
<Icon icon={icon} />
|
||||
<Text color={selected ? "black" : "gray"}>{text}</Text>
|
||||
<Text ml="2" color={selected ? "black" : "gray"}>{text}</Text>
|
||||
</HoverBoxLink>
|
||||
);
|
||||
};
|
||||
@ -57,13 +57,13 @@ export function PopoverRoutes(
|
||||
const { view } = routeProps.match.params;
|
||||
return (
|
||||
<Box
|
||||
px={[3, 7, 8]}
|
||||
px={[3, 5, 8]}
|
||||
py={[3, 5]}
|
||||
backgroundColor='scales.black30'
|
||||
left="0px"
|
||||
top="0px"
|
||||
width="100vw"
|
||||
height="100vh"
|
||||
width="100%"
|
||||
height="100%"
|
||||
zIndex={4}
|
||||
position="fixed"
|
||||
>
|
||||
@ -79,7 +79,7 @@ export function PopoverRoutes(
|
||||
<Box
|
||||
display="grid"
|
||||
gridTemplateRows={["32px 1fr", "100%"]}
|
||||
gridTemplateColumns={["100%", "200px 1fr"]}
|
||||
gridTemplateColumns={["100%", "150px 1fr"]}
|
||||
height="100%"
|
||||
width="100%"
|
||||
>
|
||||
@ -96,13 +96,13 @@ export function PopoverRoutes(
|
||||
text="Participants"
|
||||
/>
|
||||
<SidebarItem
|
||||
icon="Circle"
|
||||
icon="Gear"
|
||||
selected={view === "settings"}
|
||||
to={relativeUrl("/settings")}
|
||||
text="Group Settings"
|
||||
/>
|
||||
<SidebarItem
|
||||
icon="Circle"
|
||||
icon="Smiley"
|
||||
selected={view === "profile"}
|
||||
to={relativeUrl("/profile")}
|
||||
text="Group Profile"
|
||||
|
@ -39,12 +39,10 @@ export function Resource(props: ResourceProps) {
|
||||
<Route
|
||||
path={relativePath("/settings")}
|
||||
render={(routeProps) => {
|
||||
const title = `Channel Settings: ${association?.metadata?.title}`;
|
||||
return (
|
||||
<ResourceSkeleton
|
||||
baseUrl={props.baseUrl}
|
||||
{...skelProps}
|
||||
title={title}
|
||||
>
|
||||
<ChannelSettings api={api} association={association} />
|
||||
</ResourceSkeleton>
|
||||
|
@ -37,7 +37,8 @@ export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
return (
|
||||
<Col width="100%" height="100%" overflowY="hidden">
|
||||
<Box
|
||||
p={2}
|
||||
py="2"
|
||||
px="2"
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
borderBottom={1}
|
||||
@ -47,8 +48,9 @@ export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
<Box
|
||||
borderRight={1}
|
||||
borderRightColor="gray"
|
||||
pr={2}
|
||||
mr={2}
|
||||
pr={3}
|
||||
mr={3}
|
||||
my="1"
|
||||
display={["block", "none"]}
|
||||
>
|
||||
<Link to={`/~landscape${selectedGroup}`}> {"<- Back"}</Link>
|
||||
@ -56,8 +58,6 @@ export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
) : (
|
||||
<Box
|
||||
color="blue"
|
||||
borderRight={1}
|
||||
borderRightColor="gray"
|
||||
pr={2}
|
||||
mr={2}
|
||||
>
|
||||
@ -66,11 +66,12 @@ export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
</Link>
|
||||
</Box>
|
||||
)}
|
||||
<Box pr={1} mr={2}>
|
||||
<Text>{title}</Text>
|
||||
</Box>
|
||||
|
||||
{atRoot && (
|
||||
<>
|
||||
<Box pr={1} mr={2}>
|
||||
<Text>{title}</Text>
|
||||
</Box>
|
||||
<TruncatedBox
|
||||
display={["none", "block"]}
|
||||
maxWidth="60%"
|
||||
|
@ -62,6 +62,7 @@ interface SidebarProps {
|
||||
// is fixed
|
||||
const SidebarStickySpacer = styled(Box)`
|
||||
height: 0px;
|
||||
flex-grow: 1;
|
||||
@-moz-document url-prefix() {
|
||||
& {
|
||||
height: ${p => p.theme.space[6] }px;
|
||||
@ -88,12 +89,11 @@ export function Sidebar(props: SidebarProps) {
|
||||
<Col
|
||||
display={display}
|
||||
width="100%"
|
||||
height="100%"
|
||||
gridRow="1/2"
|
||||
gridColumn="1/2"
|
||||
borderRight={1}
|
||||
borderRightColor="washedGray"
|
||||
overflowY="auto"
|
||||
overflowY="scroll"
|
||||
fontSize={0}
|
||||
bg="white"
|
||||
position="relative"
|
||||
@ -127,12 +127,14 @@ export function Sidebar(props: SidebarProps) {
|
||||
/>
|
||||
<SidebarStickySpacer flexShrink={0} />
|
||||
<Box
|
||||
flexShrink="0"
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
position="sticky"
|
||||
bottom="8px"
|
||||
bottom={"8px"}
|
||||
width="100%"
|
||||
my={2}
|
||||
height="fit-content"
|
||||
py="2"
|
||||
>
|
||||
<Link
|
||||
to={!!groupPath ? `/~landscape${groupPath}/new` : `/~landscape/home/new`}
|
||||
|
@ -28,6 +28,7 @@ export function SidebarListHeader(props: {
|
||||
|
||||
return (
|
||||
<Row
|
||||
flexShrink="0"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
py={2}
|
||||
@ -70,7 +71,7 @@ export function SidebarListHeader(props: {
|
||||
</FormikOnBlur>
|
||||
}
|
||||
>
|
||||
<Icon color="gray" icon="Menu" />
|
||||
<Icon color="gray" icon="Adjust" />
|
||||
</Dropdown>
|
||||
</Row>
|
||||
);
|
||||
|
@ -56,8 +56,8 @@ export function Skeleton(props: SkeletonProps) {
|
||||
return (
|
||||
<Body
|
||||
display="grid"
|
||||
gridTemplateColumns={["1fr", "250px 1fr"]}
|
||||
gridTemplateRows="1fr"
|
||||
gridTemplateColumns={["100%", "250px 1fr"]}
|
||||
gridTemplateRows="100%"
|
||||
>
|
||||
{!props.hideSidebar && (
|
||||
<Sidebar
|
||||
|
Loading…
Reference in New Issue
Block a user