mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-15 01:52:42 +03:00
Merge branch 'release/next-js' of https://github.com/urbit/urbit into zustand-stores
This commit is contained in:
commit
cddbc114b9
23
pkg/interface/src/logic/lib/idling.ts
Normal file
23
pkg/interface/src/logic/lib/idling.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function useIdlingState() {
|
||||
const [idling, setIdling] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
function blur() {
|
||||
setIdling(true);
|
||||
}
|
||||
function focus() {
|
||||
setIdling(false);
|
||||
}
|
||||
window.addEventListener('blur', blur);
|
||||
window.addEventListener('focus', focus);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('blur', blur);
|
||||
window.removeEventListener('focus', focus);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return idling;
|
||||
}
|
@ -7,6 +7,7 @@ import { BackgroundConfig, RemoteContentPolicy, TutorialProgress, tutorialProgre
|
||||
|
||||
|
||||
export interface LocalState {
|
||||
theme: "light" | "dark" | "auto";
|
||||
hideAvatars: boolean;
|
||||
hideNicknames: boolean;
|
||||
remoteContentPolicy: RemoteContentPolicy;
|
||||
@ -35,6 +36,7 @@ export const selectLocalState =
|
||||
const useLocalState = create<LocalStateZus>(persist((set, get) => ({
|
||||
dark: false,
|
||||
background: undefined,
|
||||
theme: "auto",
|
||||
hideAvatars: false,
|
||||
hideNicknames: false,
|
||||
hideLeapCats: [],
|
||||
|
@ -34,7 +34,7 @@ import useGroupState from '~/logic/state/group';
|
||||
import useSettingsState from '~/logic/state/settings';
|
||||
|
||||
|
||||
const Root = withState(useSettingsState, styled.div`
|
||||
const Root = withState(styled.div`
|
||||
font-family: ${p => p.theme.fonts.sans};
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@ -50,6 +50,10 @@ const Root = withState(useSettingsState, styled.div`
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: ${ p => p.theme.colors.gray } transparent;
|
||||
@ -68,10 +72,9 @@ const Root = withState(useSettingsState, styled.div`
|
||||
border-radius: 1rem;
|
||||
border: 0px solid transparent;
|
||||
}
|
||||
`, ['display']);
|
||||
`, [[useSettingsState, 'display']]);
|
||||
|
||||
const StatusBarWithRouter = withRouter(StatusBar);
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -137,11 +140,14 @@ class App extends React.Component {
|
||||
const { state, props } = this;
|
||||
const associations = state.associations ?
|
||||
state.associations : { contacts: {} };
|
||||
const theme = props.dark ? dark : light;
|
||||
const background = this.props.background;
|
||||
|
||||
const ourContact = this.props.contacts[`~${this.ship}`] || null;
|
||||
const theme =
|
||||
((props.dark && props?.display?.theme == "auto") ||
|
||||
props?.display?.theme == "dark"
|
||||
) ? dark : light;
|
||||
|
||||
const notificationsCount = state.notificationsCount || 0;
|
||||
const doNotDisturb = state.doNotDisturb || false;
|
||||
const ourContact = this.state.contacts[`~${this.ship}`] || null;
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<Helmet>
|
||||
@ -185,6 +191,9 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default withState(useGroupState, withState(useContactState, withState(useLocalState, process.env.NODE_ENV === 'production' ? App : hot(App))));
|
||||
|
||||
|
||||
export default withState(process.env.NODE_ENV === 'production' ? App : hot(App), [
|
||||
[useGroupState],
|
||||
[useContactState],
|
||||
[useSettingsState, ['display']],
|
||||
[useLocalState]
|
||||
]);
|
@ -128,7 +128,13 @@ class ChatInput extends Component<ChatInputProps, ChatInputState> {
|
||||
props.ourContact &&
|
||||
((props.ourContact.avatar !== null) && !props.hideAvatars)
|
||||
)
|
||||
? <BaseImage src={props.ourContact.avatar} height={16} width={16} className="dib" />
|
||||
? <BaseImage
|
||||
src={props.ourContact.avatar}
|
||||
height={16}
|
||||
width={16}
|
||||
style={{ objectFit: 'cover' }}
|
||||
display='inline-block'
|
||||
/>
|
||||
: <Sigil
|
||||
ship={window.ship}
|
||||
size={16}
|
||||
|
@ -38,6 +38,7 @@ import useLocalState from '~/logic/state/local';
|
||||
import useSettingsState, {selectCalmState} from "~/logic/state/settings";
|
||||
import Timestamp from '~/views/components/Timestamp';
|
||||
import useContactState from '~/logic/state/contact';
|
||||
import {useIdlingState} from '~/logic/lib/idling';
|
||||
|
||||
export const DATESTAMP_FORMAT = '[~]YYYY.M.D';
|
||||
|
||||
@ -65,16 +66,16 @@ export const DayBreak = ({ when, shimTop = false }: DayBreakProps) => (
|
||||
|
||||
export const UnreadMarker = React.forwardRef(({ dayBreak, when, api, association }, ref) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const idling = useIdlingState();
|
||||
const dismiss = useCallback(() => {
|
||||
api.hark.markCountAsRead(association, '/', 'message');
|
||||
}, [api, association]);
|
||||
|
||||
useEffect(() => {
|
||||
if(visible) {
|
||||
console.log('dismissing');
|
||||
if(visible && !idling) {
|
||||
dismiss();
|
||||
}
|
||||
}, [visible]);
|
||||
}, [visible, idling]);
|
||||
|
||||
return (
|
||||
<Row
|
||||
@ -285,6 +286,7 @@ export const MessageAuthor = ({
|
||||
contact?.avatar && !hideAvatars ? (
|
||||
<BaseImage
|
||||
display='inline-block'
|
||||
style={{ objectFit: 'cover' }}
|
||||
src={contact.avatar}
|
||||
height={16}
|
||||
width={16}
|
||||
|
@ -85,8 +85,6 @@ export default class ChatWindow extends Component<
|
||||
|
||||
componentDidMount() {
|
||||
this.calculateUnreadIndex();
|
||||
window.addEventListener('blur', this.handleWindowBlur);
|
||||
window.addEventListener('focus', this.handleWindowFocus);
|
||||
setTimeout(() => {
|
||||
if (this.props.scrollTo) {
|
||||
this.scrollToUnread();
|
||||
@ -96,11 +94,6 @@ export default class ChatWindow extends Component<
|
||||
}, this.INITIALIZATION_MAX_TIME);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('blur', this.handleWindowBlur);
|
||||
window.removeEventListener('focus', this.handleWindowFocus);
|
||||
}
|
||||
|
||||
calculateUnreadIndex() {
|
||||
const { graph, unreadCount } = this.props;
|
||||
const unreadIndex = graph.keys()[unreadCount];
|
||||
@ -110,7 +103,6 @@ export default class ChatWindow extends Component<
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log(`found unread: ${unreadIndex}`);
|
||||
this.setState({
|
||||
unreadIndex
|
||||
});
|
||||
@ -198,7 +190,6 @@ export default class ChatWindow extends Component<
|
||||
this.calculateUnreadIndex();
|
||||
}
|
||||
this.fetchPending = false;
|
||||
console.log(currSize, graph.size);
|
||||
return currSize === graph.size;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,18 @@ const renderers = {
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
blockquote: ({ children }) => {
|
||||
return (
|
||||
<Text
|
||||
lineHeight="20px"
|
||||
display="block"
|
||||
borderLeft="1px solid"
|
||||
color="black"
|
||||
paddingLeft={2}>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
},
|
||||
paragraph: ({ children }) => {
|
||||
return (
|
||||
<Text fontSize='1' lineHeight={'20px'}>
|
||||
|
@ -50,12 +50,6 @@ button {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 400;
|
||||
}
|
||||
@ -80,10 +74,6 @@ h2 {
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
}
|
||||
|
||||
.bg-welcome-green {
|
||||
background-color: #ecf6f2;
|
||||
}
|
||||
|
||||
.c-default {
|
||||
cursor: default;
|
||||
}
|
||||
@ -158,38 +148,11 @@ h2 {
|
||||
/* responsive */
|
||||
|
||||
@media all and (max-width: 34.375em) {
|
||||
.dn-s {
|
||||
display: none;
|
||||
}
|
||||
.flex-basis-full-s {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
.h-100-minus-96-s {
|
||||
height: calc(100% - 96px);
|
||||
}
|
||||
.unread-notice {
|
||||
top: 96px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 34.375em) and (max-width: 46.875em) {
|
||||
.flex-basis-250-m {
|
||||
flex-basis: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 46.875em) and (max-width: 60em) {
|
||||
.flex-basis-250-l {
|
||||
flex-basis: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 60em) {
|
||||
.flex-basis-250-xl {
|
||||
flex-basis: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0 0 0 16px;
|
||||
margin: 0;
|
||||
@ -345,79 +308,13 @@ pre.CodeMirror-placeholder.CodeMirror-line-like {
|
||||
/* dark */
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.bg-black-d {
|
||||
background-color: black;
|
||||
}
|
||||
.white-d {
|
||||
color: white;
|
||||
}
|
||||
.gray1-d {
|
||||
color: #4d4d4d;
|
||||
}
|
||||
.gray2-d {
|
||||
color: #7f7f7f;
|
||||
}
|
||||
.gray3-d {
|
||||
color: #b1b2b3;
|
||||
}
|
||||
.gray4-d {
|
||||
color: #e6e6e6;
|
||||
}
|
||||
.bg-gray0-d {
|
||||
background-color: #333;
|
||||
}
|
||||
.bg-gray1-d {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
.b--gray0-d {
|
||||
border-color: #333;
|
||||
}
|
||||
.b--gray1-d {
|
||||
border-color: #4d4d4d;
|
||||
}
|
||||
.b--gray2-d {
|
||||
border-color: #7f7f7f;
|
||||
}
|
||||
.b--white-d {
|
||||
border-color: #fff;
|
||||
}
|
||||
.b--green2-d {
|
||||
border-color: #2aa779;
|
||||
}
|
||||
.bb-d {
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
}
|
||||
.invert-d {
|
||||
filter: invert(1);
|
||||
}
|
||||
.o-80-d {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.focus-b--white-d:focus {
|
||||
border-color: #fff;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
.hover-bg-gray1-d:hover {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
blockquote {
|
||||
border-left: 1px solid white;
|
||||
}
|
||||
|
||||
.contrast-10-d {
|
||||
filter: contrast(0.1);
|
||||
}
|
||||
|
||||
.bg-none-d {
|
||||
background: none;
|
||||
border-left: 1px solid inherit;
|
||||
}
|
||||
|
||||
/* codemirror */
|
||||
.chat .cm-s-tlon.CodeMirror {
|
||||
color: #fff;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.chat .cm-s-tlon span.cm-def {
|
||||
@ -468,7 +365,7 @@ pre.CodeMirror-placeholder.CodeMirror-line-like {
|
||||
/* set rules w/ both color & bg-color last to preserve legibility */
|
||||
.chat .CodeMirror-selected {
|
||||
background: var(--medium-gray) !important;
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.chat .cm-s-tlon span.cm-comment {
|
||||
|
@ -17,7 +17,6 @@ export default class CustomTile extends React.PureComponent {
|
||||
>
|
||||
<BaseImage
|
||||
position='absolute'
|
||||
className="invert-d"
|
||||
style={{ left: 38, top: 38 }}
|
||||
src='/~launch/img/UnknownCustomTile.png'
|
||||
width='48px'
|
||||
|
@ -53,25 +53,10 @@ button {
|
||||
|
||||
/* dark */
|
||||
@media all and (prefers-color-scheme: dark) {
|
||||
.bg-gray0-d {
|
||||
background-color: #333;
|
||||
}
|
||||
.bg-gray1-d {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
.bg-gray2-d {
|
||||
background-color: #7f7f7f;
|
||||
}
|
||||
.b--gray1-d {
|
||||
border-color: #4d4d4d;
|
||||
}
|
||||
.white-d {
|
||||
color: #fff;
|
||||
}
|
||||
.invert-d {
|
||||
filter: invert(1);
|
||||
}
|
||||
.hover-bg-gray1-d:hover {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
}
|
||||
|
@ -16,23 +16,4 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* responsive */
|
||||
@media all and (max-width: 34.375em) {
|
||||
.dn-s {
|
||||
display: none;
|
||||
}
|
||||
.flex-basis-100-s, .flex-basis-full-s {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 34.375em) {
|
||||
.db-ns {
|
||||
display: block;
|
||||
}
|
||||
.flex-basis-30-ns {
|
||||
flex-basis: 30vw;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import moment from 'moment';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { BigInteger } from 'big-integer';
|
||||
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
import { Box, Text } from '@tlon/indigo-react';
|
||||
import { Graph } from '@urbit/api';
|
||||
|
||||
import { getLatestRevision } from '~/logic/lib/publish';
|
||||
@ -24,13 +24,14 @@ function NavigationItem(props: {
|
||||
textAlign={props.prev ? 'left' : 'right'}
|
||||
>
|
||||
<Link to={props.url}>
|
||||
<Box color="gray" mb={2}>
|
||||
<Text display='block' color="gray">
|
||||
{props.prev ? 'Previous' : 'Next'}
|
||||
</Box>
|
||||
<Box mb={1}>{props.title}</Box>
|
||||
</Text>
|
||||
<Text display='block' lineHeight="tall">{props.title}</Text>
|
||||
<Timestamp
|
||||
stamp={moment(props.date)}
|
||||
time={false}
|
||||
fontSize="1"
|
||||
justifyContent={props.prev ? 'flex-start' : 'flex-end'}
|
||||
/>
|
||||
</Link>
|
||||
|
@ -5,41 +5,6 @@
|
||||
--light-gray: rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.bg-welcome-green {
|
||||
background-color: #ECF6F2;
|
||||
}
|
||||
|
||||
@media all and (max-width: 34.375em) {
|
||||
.dn-s {
|
||||
display: none;
|
||||
}
|
||||
.flex-basis-100-s, .flex-basis-full-s {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
.h-100-m-40-s {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
.black-s {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 34.375em) {
|
||||
.db-ns {
|
||||
display: block;
|
||||
}
|
||||
.flex-basis-250-ns {
|
||||
flex-basis: 250px;
|
||||
}
|
||||
.h-100-m-40-ns {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
|
||||
.bg-light-green {
|
||||
background: rgba(42, 167, 121, 0.1);
|
||||
}
|
||||
|
||||
.NotebookButton {
|
||||
border-radius:2px;
|
||||
cursor: pointer;
|
||||
@ -207,57 +172,6 @@
|
||||
}
|
||||
|
||||
@media all and (prefers-color-scheme: dark) {
|
||||
.bg-black-d {
|
||||
background-color: black;
|
||||
}
|
||||
.white-d {
|
||||
color: white;
|
||||
}
|
||||
.gray1-d {
|
||||
color: #4d4d4d;
|
||||
}
|
||||
.gray2-d {
|
||||
color: #7f7f7f;
|
||||
}
|
||||
.gray3-d {
|
||||
color: #b1b2b3;
|
||||
}
|
||||
.gray4-d {
|
||||
color: #e6e6e6;
|
||||
}
|
||||
.bg-gray0-d {
|
||||
background-color: #333;
|
||||
}
|
||||
.bg-gray1-d {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
.b--gray0-d {
|
||||
border-color: #333;
|
||||
}
|
||||
.b--gray1-d {
|
||||
border-color: #4d4d4d;
|
||||
}
|
||||
.b--gray2-d {
|
||||
border-color: #7f7f7f;
|
||||
}
|
||||
.b--white-d {
|
||||
border-color: #fff;
|
||||
}
|
||||
.invert-d {
|
||||
filter: invert(1);
|
||||
}
|
||||
.o-60-d {
|
||||
opacity: .6;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
.focus-b--white-d:focus {
|
||||
border-color: #fff;
|
||||
}
|
||||
.hover-bg-gray1-d:hover {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
.options.open {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
@ -266,32 +180,32 @@
|
||||
}
|
||||
.publish .cm-s-tlon.CodeMirror {
|
||||
background: unset;
|
||||
color: #fff;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.publish .cm-s-tlon span.cm-def {
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.publish .cm-s-tlon span.cm-variable {
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.publish .cm-s-tlon span.cm-variable-2 {
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.publish .cm-s-tlon span.cm-variable-3,
|
||||
.publish .cm-s-tlon span.cm-type {
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.publish .cm-s-tlon span.cm-property {
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.publish .cm-s-tlon span.cm-operator {
|
||||
color: white;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
@ -325,7 +239,7 @@
|
||||
color: black;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
background-color: rgba(255,255,255, 0.3);
|
||||
background-color: rgba(0,255,255, 0.3);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ import React from "react";
|
||||
import {
|
||||
Col,
|
||||
Text,
|
||||
Label,
|
||||
ManagedRadioButtonField as Radio
|
||||
} from "@tlon/indigo-react";
|
||||
import { Formik, Form } from "formik";
|
||||
import * as Yup from "yup";
|
||||
@ -20,13 +22,16 @@ const formSchema = Yup.object().shape({
|
||||
.oneOf(["none", "color", "url"], "invalid")
|
||||
.required("Required"),
|
||||
background: Yup.string(),
|
||||
|
||||
theme: Yup.string()
|
||||
.oneOf(["light", "dark", "auto"])
|
||||
.required("Required")
|
||||
});
|
||||
|
||||
interface FormSchema {
|
||||
bgType: BgType;
|
||||
bgColor: string | undefined;
|
||||
bgUrl: string | undefined;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
interface DisplayFormProps {
|
||||
@ -42,6 +47,7 @@ export default function DisplayForm(props: DisplayFormProps) {
|
||||
display: {
|
||||
background,
|
||||
backgroundType,
|
||||
theme
|
||||
}
|
||||
} = useSettingsState(settingsSel);
|
||||
|
||||
@ -62,13 +68,13 @@ export default function DisplayForm(props: DisplayFormProps) {
|
||||
{
|
||||
bgType: backgroundType,
|
||||
bgColor: bgColor || "",
|
||||
bgUrl
|
||||
bgUrl,
|
||||
theme
|
||||
} as FormSchema
|
||||
}
|
||||
onSubmit={async (values, actions) => {
|
||||
let promises = [] as Promise<any>[];
|
||||
promises.push(api.settings.putEntry('display', 'backgroundType', values.bgType));
|
||||
|
||||
promises.push(
|
||||
api.settings.putEntry('display', 'background',
|
||||
values.bgType === "color"
|
||||
@ -78,6 +84,7 @@ export default function DisplayForm(props: DisplayFormProps) {
|
||||
: false
|
||||
));
|
||||
|
||||
promises.push(api.settings.putEntry('display', 'theme', values.theme));
|
||||
await Promise.all(promises);
|
||||
|
||||
actions.setStatus({ success: null });
|
||||
@ -101,6 +108,10 @@ export default function DisplayForm(props: DisplayFormProps) {
|
||||
bgUrl={props.values.bgUrl}
|
||||
api={api}
|
||||
/>
|
||||
<Label>Theme</Label>
|
||||
<Radio name="theme" id="light" label="Light"/>
|
||||
<Radio name="theme" id="dark" label="Dark" />
|
||||
<Radio name="theme" id="auto" label="Auto" />
|
||||
<AsyncButton primary width="fit-content" type="submit">
|
||||
Save
|
||||
</AsyncButton>
|
||||
|
@ -48,6 +48,7 @@ export default function Author(props: AuthorProps): ReactElement {
|
||||
<BaseImage
|
||||
display='inline-block'
|
||||
src={contact.avatar}
|
||||
style={{ objectFit: 'cover' }}
|
||||
height={16}
|
||||
width={16}
|
||||
/>
|
||||
|
@ -98,6 +98,7 @@ class ProfileOverlay extends PureComponent<
|
||||
contact?.avatar && !hideAvatars ? (
|
||||
<BaseImage
|
||||
display='inline-block'
|
||||
style={{ objectFit: 'cover' }}
|
||||
src={contact.avatar}
|
||||
height={72}
|
||||
width={72}
|
||||
|
@ -46,6 +46,18 @@ const RichText = React.memo(({ disableRemoteContent, ...props }) => (
|
||||
}
|
||||
return linkText;
|
||||
},
|
||||
blockquote: (blockquoteProps) => {
|
||||
return (
|
||||
<Text
|
||||
lineHeight="20px"
|
||||
display="block"
|
||||
borderLeft="1px solid"
|
||||
color="black"
|
||||
paddingLeft={2} {...props}>
|
||||
{blockquoteProps.children}
|
||||
</Text>
|
||||
)
|
||||
},
|
||||
paragraph: (paraProps) => {
|
||||
return <Text display={props.inline ? 'inline' : 'block'} mb='2' {...props}>{paraProps.children}</Text>;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ const ZONE_SIZE = IS_IOS ? 10 : 40;
|
||||
|
||||
export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T>, VirtualScrollerState<T>> {
|
||||
/**
|
||||
* A reference to our scroll container
|
||||
* A reference to our scroll container
|
||||
*/
|
||||
private window: HTMLDivElement | null = null;
|
||||
/**
|
||||
@ -110,12 +110,10 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
scrollbar: 0
|
||||
};
|
||||
|
||||
this.updateVisible = IS_IOS
|
||||
? _.debounce(this.updateVisible.bind(this), 100)
|
||||
: this.updateVisible.bind(this);
|
||||
this.updateVisible = this.updateVisible.bind(this);
|
||||
|
||||
this.invertedKeyHandler = this.invertedKeyHandler.bind(this);
|
||||
this.onScroll = IS_IOS ? _.debounce(this.onScroll.bind(this), 150) : this.onScroll.bind(this);
|
||||
this.onScroll = IS_IOS ? _.debounce(this.onScroll.bind(this), 400) : this.onScroll.bind(this);
|
||||
this.scrollKeyMap = this.scrollKeyMap.bind(this);
|
||||
this.setWindow = this.setWindow.bind(this);
|
||||
}
|
||||
@ -153,10 +151,6 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
if(size !== prevProps.size) {
|
||||
if(this.scrollLocked) {
|
||||
this.updateVisible(0);
|
||||
if(IS_IOS) {
|
||||
(this.updateVisible as any).flush();
|
||||
|
||||
}
|
||||
this.resetScroll();
|
||||
|
||||
}
|
||||
@ -168,7 +162,7 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
}
|
||||
|
||||
startOffset() {
|
||||
const startIndex = this.state.visibleItems.peekLargest()?.[0];
|
||||
const startIndex = this.state?.visibleItems?.peekLargest()?.[0];
|
||||
if(!startIndex) {
|
||||
return 0;
|
||||
}
|
||||
@ -321,7 +315,7 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
if(newOffset !== startOffset) {
|
||||
this.updateVisible(newOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scrollTop + windowHeight >= scrollHeight - ZONE_SIZE) {
|
||||
this.scrollLocked = false;
|
||||
log('scroll', `Entered end zone ${scrollTop}`);
|
||||
@ -351,7 +345,7 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
log('bail', 'Deep restore');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const ref = this.childRefs.get(this.savedIndex)!;
|
||||
const newScrollTop = this.window.scrollHeight - ref.offsetTop - this.savedDistance;
|
||||
|
||||
@ -371,9 +365,6 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
return;
|
||||
}
|
||||
this.updateVisible(Math.max(offset - this.pageDelta, 0));
|
||||
if(IS_IOS) {
|
||||
(this.updateVisible as any).flush();
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
ref = this.childRefs.get(index);
|
||||
this.savedIndex = null;
|
||||
@ -382,7 +373,7 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
|
||||
ref?.scrollIntoView({ block: 'center' });
|
||||
});
|
||||
} else {
|
||||
} else {
|
||||
this.savedIndex = null;
|
||||
this.savedDistance = 0;
|
||||
this.saveDepth = 0;
|
||||
@ -458,9 +449,11 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
|
||||
const transform = isTop ? 'scale3d(1, 1, 1)' : 'scale3d(1, -1, 1)';
|
||||
|
||||
const atStart = this.props.data.peekLargest()![0].eq(visibleItems.peekLargest()?.[0] || bigInt.zero)
|
||||
const atEnd = false;
|
||||
|
||||
const loaded = this.props.data.size > 0;
|
||||
|
||||
const atStart = loaded && this.props.data.peekLargest()?.[0].eq(visibleItems.peekLargest()?.[0] || bigInt.zero);
|
||||
const atEnd = this.loaded.top;
|
||||
|
||||
return (
|
||||
<>
|
||||
{!IS_IOS && (<Box borderRadius="3" top ={isTop ? "0" : undefined} bottom={!isTop ? "0" : undefined} ref={el => { this.scrollRef = el; }} right="0" height="50px" position="absolute" width="4px" backgroundColor="lightGray" />)}
|
||||
@ -477,11 +470,11 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
||||
setRef={this.setRef}
|
||||
index={index}
|
||||
scrollWindow={this.window}
|
||||
renderer={renderer}
|
||||
renderer={renderer}
|
||||
/>
|
||||
))}
|
||||
</VirtualContext.Provider>
|
||||
{(!isTop ? !atStart : !atEnd) &&
|
||||
{(!isTop ? !atStart : !atEnd) &&
|
||||
(<Center height="5">
|
||||
<LoadingSpinner />
|
||||
</Center>)}
|
||||
@ -508,4 +501,4 @@ function VirtualChild(props: VirtualChildProps) {
|
||||
|
||||
return (<Renderer ref={ref} {...rest} />);
|
||||
};
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
Row,
|
||||
Text,
|
||||
Icon,
|
||||
Image,
|
||||
Action,
|
||||
StatelessTextInput as Input
|
||||
} from '@tlon/indigo-react';
|
||||
@ -298,7 +299,13 @@ function Participant(props: {
|
||||
|
||||
const avatar =
|
||||
contact?.avatar !== null && !hideAvatars ? (
|
||||
<img src={contact.avatar} height={32} width={32} className="dib" />
|
||||
<Image
|
||||
src={contact.avatar}
|
||||
height={32}
|
||||
width={32}
|
||||
display='inline-block'
|
||||
style={{ objectFit: 'cover' }}
|
||||
/>
|
||||
) : (
|
||||
<Sigil ship={contact.patp} size={32} color={`#${color}`} />
|
||||
);
|
||||
|
@ -91,7 +91,7 @@ export function ResourceSkeleton(props: ResourceSkeletonProps): ReactElement {
|
||||
display={['block', 'none']}
|
||||
flexShrink={0}
|
||||
>
|
||||
<Link to={`/~landscape${workspace}`}> {'<- Back'}</Link>
|
||||
<Link to={`/~landscape${workspace}`}><Text>{'<- Back'}</Text></Link>
|
||||
</Box>
|
||||
<Box px={1} mr={2} minWidth={0} display="flex" flexShrink={[1, 0]}>
|
||||
<Text
|
||||
|
@ -4,29 +4,4 @@
|
||||
|
||||
.m0a {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* responsive */
|
||||
@media all and (max-width: 34.375em) {
|
||||
.dn-s {
|
||||
display: none;
|
||||
}
|
||||
.flex-basis-100-s {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 34.375em) {
|
||||
.db-ns {
|
||||
display: block;
|
||||
}
|
||||
.flex-basis-30-ns {
|
||||
flex-basis: 30vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (prefers-color-scheme: dark) {
|
||||
.o-60-d {
|
||||
opacity: .6;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user