mirror of
https://github.com/urbit/shrub.git
synced 2024-12-26 05:23:35 +03:00
Merge branch 'dist' into hm/grid-tweaks
This commit is contained in:
commit
082a4c66ec
13
pkg/arvo/mar/kiln/pause.hoon
Normal file
13
pkg/arvo/mar/kiln/pause.hoon
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|_ =desk
|
||||||
|
++ grad %noun
|
||||||
|
++ grow
|
||||||
|
|%
|
||||||
|
++ noun desk
|
||||||
|
++ json s+desk
|
||||||
|
--
|
||||||
|
++ grab
|
||||||
|
|%
|
||||||
|
++ noun ^desk
|
||||||
|
++ json so:dejs:format
|
||||||
|
--
|
||||||
|
--
|
0
pkg/arvo/mar/kiln/resume.hoon
Normal file
0
pkg/arvo/mar/kiln/resume.hoon
Normal file
@ -243,6 +243,7 @@
|
|||||||
%- pairs
|
%- pairs
|
||||||
:~ ship+s+(scot %p ship.rail.a)
|
:~ ship+s+(scot %p ship.rail.a)
|
||||||
desk+s+desk.rail.a
|
desk+s+desk.rail.a
|
||||||
|
paused+b+paused.rail.a
|
||||||
aeon+(numb aeon.rail.a)
|
aeon+(numb aeon.rail.a)
|
||||||
next+a+(turn next.a rung)
|
next+a+(turn next.a rung)
|
||||||
rein+(rein rein.a)
|
rein+(rein rein.a)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
title+'Bitcoin'
|
title+'Bitcoin'
|
||||||
info+'BTC wallet for Urbit. Testing'
|
info+'BTC wallet for Urbit. Testing'
|
||||||
color+0xf9.8e40
|
color+0xf9.8e40
|
||||||
glob-http+'https://bootstrap.urbit.org/glob-0v2.sl9s6.ud2bs.l9ft0.mstja.5f8kt.glob'
|
glob-http+'https://bootstrap.urbit.org/glob-0v4.ghaim.of1as.9ucee.uj93f.a9nbs.glob'
|
||||||
image+'https://urbit.ewr1.vultrobjects.com/hastuc-dibtux/2021.8.24..02.57.38-bitcoin.svg'
|
image+'https://urbit.ewr1.vultrobjects.com/hastuc-dibtux/2021.8.24..02.57.38-bitcoin.svg'
|
||||||
base+'bitcoin'
|
base+'bitcoin'
|
||||||
version+[0 0 1]
|
version+[0 0 1]
|
||||||
|
@ -55,7 +55,7 @@ module.exports = {
|
|||||||
filename: (pathData) => {
|
filename: (pathData) => {
|
||||||
return pathData.chunk.name === 'app' ? 'index.[contenthash].js' : '[name].js';
|
return pathData.chunk.name === 'app' ? 'index.[contenthash].js' : '[name].js';
|
||||||
},
|
},
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, '../dist'),
|
||||||
publicPath: '/apps/bitcoin/',
|
publicPath: '/apps/bitcoin/',
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
|
@ -5,23 +5,25 @@ import { Grid } from './pages/Grid';
|
|||||||
import useDocketState from './state/docket';
|
import useDocketState from './state/docket';
|
||||||
import { PermalinkRoutes } from './pages/PermalinkRoutes';
|
import { PermalinkRoutes } from './pages/PermalinkRoutes';
|
||||||
import useKilnState from './state/kiln';
|
import useKilnState from './state/kiln';
|
||||||
import { usePreferencesStore } from './nav/preferences/usePreferencesStore';
|
|
||||||
import useContactState from './state/contact';
|
import useContactState from './state/contact';
|
||||||
import api from './state/api';
|
import api from './state/api';
|
||||||
import { useMedia } from './logic/useMedia';
|
import { useMedia } from './logic/useMedia';
|
||||||
|
import { useHarkStore } from './state/hark';
|
||||||
|
import { useTheme } from './state/settings';
|
||||||
|
import { useLocalState } from './state/local';
|
||||||
|
|
||||||
const AppRoutes = () => {
|
const AppRoutes = () => {
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
const theme = usePreferencesStore((s) => s.theme);
|
const theme = useTheme();
|
||||||
const isDarkMode = useMedia('(prefers-color-scheme: dark)');
|
const isDarkMode = useMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ((isDarkMode && theme === 'automatic') || theme === 'dark') {
|
if ((isDarkMode && theme === 'auto') || theme === 'dark') {
|
||||||
document.body.classList.add('dark');
|
document.body.classList.add('dark');
|
||||||
usePreferencesStore.setState({ currentTheme: 'dark' });
|
useLocalState.setState({ currentTheme: 'dark' });
|
||||||
} else {
|
} else {
|
||||||
document.body.classList.remove('dark');
|
document.body.classList.remove('dark');
|
||||||
usePreferencesStore.setState({ currentTheme: 'light' });
|
useLocalState.setState({ currentTheme: 'light' });
|
||||||
}
|
}
|
||||||
}, [isDarkMode, theme]);
|
}, [isDarkMode, theme]);
|
||||||
|
|
||||||
@ -35,6 +37,7 @@ const AppRoutes = () => {
|
|||||||
fetchVats();
|
fetchVats();
|
||||||
fetchLag();
|
fetchLag();
|
||||||
useContactState.getState().initialize(api);
|
useContactState.getState().initialize(api);
|
||||||
|
useHarkStore.getState().initialize(api);
|
||||||
|
|
||||||
Mousetrap.bind(['command+/', 'ctrl+/'], () => {
|
Mousetrap.bind(['command+/', 'ctrl+/'], () => {
|
||||||
push('/leap/search');
|
push('/leap/search');
|
||||||
|
@ -3,7 +3,7 @@ import React, { useMemo } from 'react';
|
|||||||
import { sigil, reactRenderer } from '@tlon/sigil-js';
|
import { sigil, reactRenderer } from '@tlon/sigil-js';
|
||||||
import { deSig, Contact } from '@urbit/api';
|
import { deSig, Contact } from '@urbit/api';
|
||||||
import { darken, lighten, parseToHsla } from 'color2k';
|
import { darken, lighten, parseToHsla } from 'color2k';
|
||||||
import { usePreferencesStore } from '../nav/preferences/usePreferencesStore';
|
import { useCurrentTheme } from '../state/local';
|
||||||
|
|
||||||
export type AvatarSizes = 'xs' | 'small' | 'default';
|
export type AvatarSizes = 'xs' | 'small' | 'default';
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ function themeAdjustColor(color: string, theme: 'light' | 'dark'): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Avatar = ({ size, className, ...ship }: AvatarProps) => {
|
export const Avatar = ({ size, className, ...ship }: AvatarProps) => {
|
||||||
const currentTheme = usePreferencesStore((s) => s.currentTheme);
|
const currentTheme = useCurrentTheme();
|
||||||
const { shipName, color, avatar } = { ...emptyContact, ...ship };
|
const { shipName, color, avatar } = { ...emptyContact, ...ship };
|
||||||
const { classes, size: sigilSize } = sizeMap[size];
|
const { classes, size: sigilSize } = sizeMap[size];
|
||||||
const adjustedColor = themeAdjustColor(color, currentTheme);
|
const adjustedColor = themeAdjustColor(color, currentTheme);
|
||||||
|
@ -20,14 +20,14 @@ export const Setting: FC<SettingsProps> = ({ name, on, toggle, className, childr
|
|||||||
<h3 id={id} className="flex items-center h4 mb-2">
|
<h3 id={id} className="flex items-center h4 mb-2">
|
||||||
{name} {status === 'loading' && <Spinner className="ml-2" />}
|
{name} {status === 'loading' && <Spinner className="ml-2" />}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Toggle
|
<Toggle
|
||||||
aria-labelledby={id}
|
aria-labelledby={id}
|
||||||
pressed={on}
|
pressed={on}
|
||||||
onPressedChange={call}
|
onPressedChange={call}
|
||||||
className="text-blue-400"
|
className="flex-none self-start text-blue-400"
|
||||||
/>
|
/>
|
||||||
<div className="flex-1 space-y-6">{children}</div>
|
<div className="flex-1 flex flex-col justify-center space-y-6">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
@ -6,12 +6,13 @@ import type * as Polymorphic from '@radix-ui/react-polymorphic';
|
|||||||
type ToggleComponent = Polymorphic.ForwardRefComponent<
|
type ToggleComponent = Polymorphic.ForwardRefComponent<
|
||||||
Polymorphic.IntrinsicElement<typeof RadixToggle.Root>,
|
Polymorphic.IntrinsicElement<typeof RadixToggle.Root>,
|
||||||
Polymorphic.OwnProps<typeof RadixToggle.Root> & {
|
Polymorphic.OwnProps<typeof RadixToggle.Root> & {
|
||||||
|
toggleClass?: string;
|
||||||
knobClass?: string;
|
knobClass?: string;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const Toggle = React.forwardRef(
|
export const Toggle = React.forwardRef(
|
||||||
({ defaultPressed, pressed, onPressedChange, disabled, className }, ref) => {
|
({ defaultPressed, pressed, onPressedChange, disabled, className, toggleClass }, ref) => {
|
||||||
const [on, setOn] = useState(defaultPressed);
|
const [on, setOn] = useState(defaultPressed);
|
||||||
const isControlled = !!onPressedChange;
|
const isControlled = !!onPressedChange;
|
||||||
const proxyPressed = isControlled ? pressed : on;
|
const proxyPressed = isControlled ? pressed : on;
|
||||||
@ -20,14 +21,14 @@ export const Toggle = React.forwardRef(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RadixToggle.Root
|
<RadixToggle.Root
|
||||||
className="default-ring rounded-full"
|
className={classNames('default-ring rounded-full', className)}
|
||||||
pressed={proxyPressed}
|
pressed={proxyPressed}
|
||||||
onPressedChange={proxyOnPressedChange}
|
onPressedChange={proxyOnPressedChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className={classNames('w-12 h-8', className)}
|
className={classNames('w-12 h-8', toggleClass)}
|
||||||
viewBox="0 0 48 32"
|
viewBox="0 0 48 32"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { PropsWithChildren, useCallback } from 'react';
|
||||||
import { Link, Route, RouteComponentProps, Switch, useRouteMatch } from 'react-router-dom';
|
import { Link, Route, RouteComponentProps, Switch, useRouteMatch } from 'react-router-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { NotificationPrefs } from './preferences/NotificationPrefs';
|
import { NotificationPrefs } from './preferences/NotificationPrefs';
|
||||||
@ -6,32 +6,30 @@ import { SystemUpdatePrefs } from './preferences/SystemUpdatePrefs';
|
|||||||
import notificationsSVG from '../assets/notifications.svg';
|
import notificationsSVG from '../assets/notifications.svg';
|
||||||
import systemUpdatesSVG from '../assets/system-updates.svg';
|
import systemUpdatesSVG from '../assets/system-updates.svg';
|
||||||
import { InterfacePrefs } from './preferences/InterfacePrefs';
|
import { InterfacePrefs } from './preferences/InterfacePrefs';
|
||||||
|
import { useCharges } from '../state/docket';
|
||||||
|
import { AppPrefs } from './preferences/AppPrefs';
|
||||||
|
import { DocketImage } from '../components/DocketImage';
|
||||||
|
|
||||||
interface SystemPreferencesSectionProps extends RouteComponentProps<{ submenu: string }> {
|
interface SystemPreferencesSectionProps {
|
||||||
submenu: string;
|
url: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
text: string;
|
|
||||||
icon?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SystemPreferencesSection({
|
function SystemPreferencesSection({
|
||||||
match,
|
url,
|
||||||
submenu,
|
|
||||||
active,
|
active,
|
||||||
icon,
|
children
|
||||||
text
|
}: PropsWithChildren<SystemPreferencesSectionProps>) {
|
||||||
}: SystemPreferencesSectionProps) {
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<Link
|
<Link
|
||||||
to={`${match.url}/${submenu}`}
|
to={url}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex items-center px-5 py-3 hover:text-black hover:bg-gray-100',
|
'flex items-center px-2 py-2 hover:text-black hover:bg-gray-100 rounded-xl',
|
||||||
active && 'text-black bg-gray-100'
|
active && 'text-black bg-gray-100'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{icon ? <img className="w-8 h-8 mr-3" src={icon} alt="" /> : null}
|
{children}
|
||||||
{text}
|
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@ -39,53 +37,72 @@ function SystemPreferencesSection({
|
|||||||
|
|
||||||
export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }>) => {
|
export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }>) => {
|
||||||
const { match } = props;
|
const { match } = props;
|
||||||
const subMatch = useRouteMatch<{ submenu: string }>(`${match.url}/:submenu`);
|
const subMatch = useRouteMatch<{ submenu: string; desk?: string }>(
|
||||||
|
`${match.url}/:submenu/:desk?`
|
||||||
|
);
|
||||||
|
const charges = useCharges();
|
||||||
|
|
||||||
const matchSub = useCallback(
|
const matchSub = useCallback(
|
||||||
(target: string) => {
|
(target: string, desk?: string) => {
|
||||||
if (!subMatch && target === 'notifications') {
|
if (!subMatch && target === 'notifications') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (desk && subMatch?.params.desk !== desk) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return subMatch?.params.submenu === target;
|
return subMatch?.params.submenu === target;
|
||||||
},
|
},
|
||||||
[match, subMatch]
|
[match, subMatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const subUrl = useCallback((submenu: string) => `${match.url}/${submenu}`, [match]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full overflow-y-auto">
|
<div className="flex h-full overflow-y-auto">
|
||||||
<aside className="flex-none min-w-60">
|
<aside className="flex-none self-start min-w-60 py-8 font-semibold border-r-2 border-gray-50">
|
||||||
<div className="p-8">
|
<nav className="px-6">
|
||||||
<input className="input h4 default-ring bg-gray-50" placeholder="Search Preferences" />
|
<ul>
|
||||||
</div>
|
|
||||||
<nav className="border-b-2 border-gray-50">
|
|
||||||
<ul className="font-semibold">
|
|
||||||
<SystemPreferencesSection
|
<SystemPreferencesSection
|
||||||
{...props}
|
url={subUrl('notifications')}
|
||||||
text="Notifications"
|
|
||||||
icon={notificationsSVG}
|
|
||||||
submenu="notifications"
|
|
||||||
active={matchSub('notifications')}
|
active={matchSub('notifications')}
|
||||||
/>
|
>
|
||||||
|
<img className="w-8 h-8 mr-3" src={notificationsSVG} alt="" />
|
||||||
|
Notifications
|
||||||
|
</SystemPreferencesSection>
|
||||||
<SystemPreferencesSection
|
<SystemPreferencesSection
|
||||||
{...props}
|
url={subUrl('system-updates')}
|
||||||
text="System Updates"
|
|
||||||
icon={systemUpdatesSVG}
|
|
||||||
submenu="system-updates"
|
|
||||||
active={matchSub('system-updates')}
|
active={matchSub('system-updates')}
|
||||||
/>
|
>
|
||||||
<SystemPreferencesSection
|
<img className="w-8 h-8 mr-3" src={systemUpdatesSVG} alt="" />
|
||||||
{...props}
|
System Updates
|
||||||
text="Interface Settings"
|
</SystemPreferencesSection>
|
||||||
icon={systemUpdatesSVG}
|
<SystemPreferencesSection url={subUrl('interface')} active={matchSub('interface')}>
|
||||||
submenu="interface"
|
<img className="w-8 h-8 mr-3" src={systemUpdatesSVG} alt="" />
|
||||||
active={matchSub('interface')}
|
Interface Settings
|
||||||
/>
|
</SystemPreferencesSection>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<hr className="my-4 border-t-2 border-gray-50" />
|
||||||
|
<nav className="px-6">
|
||||||
|
<ul>
|
||||||
|
{Object.values(charges).map((charge) => (
|
||||||
|
<SystemPreferencesSection
|
||||||
|
key={charge.desk}
|
||||||
|
url={subUrl(`apps/${charge.desk}`)}
|
||||||
|
active={matchSub('apps', charge.desk)}
|
||||||
|
>
|
||||||
|
<DocketImage size="small" className="mr-3" {...charge} />
|
||||||
|
{charge.title}
|
||||||
|
</SystemPreferencesSection>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
<section className="flex-1 min-h-[600px] p-8 text-black border-l-2 border-gray-50">
|
<section className="flex-1 min-h-[600px] p-8 text-black">
|
||||||
<Switch>
|
<Switch>
|
||||||
|
<Route path={`${match.url}/apps/:desk`} component={AppPrefs} />
|
||||||
<Route path={`${match.url}/system-updates`} component={SystemUpdatePrefs} />
|
<Route path={`${match.url}/system-updates`} component={SystemUpdatePrefs} />
|
||||||
<Route path={`${match.url}/interface`} component={InterfacePrefs} />
|
<Route path={`${match.url}/interface`} component={InterfacePrefs} />
|
||||||
<Route path={[`${match.url}/notifications`, match.url]} component={NotificationPrefs} />
|
<Route path={[`${match.url}/notifications`, match.url]} component={NotificationPrefs} />
|
||||||
|
33
pkg/grid/src/nav/preferences/AppPrefs.tsx
Normal file
33
pkg/grid/src/nav/preferences/AppPrefs.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { RouteComponentProps } from 'react-router-dom';
|
||||||
|
import { Setting } from '../../components/Setting';
|
||||||
|
import { ShipName } from '../../components/ShipName';
|
||||||
|
import { useCharge } from '../../state/docket';
|
||||||
|
import useKilnState, { useVat } from '../../state/kiln';
|
||||||
|
|
||||||
|
export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => {
|
||||||
|
const { desk } = match.params;
|
||||||
|
const charge = useCharge(desk);
|
||||||
|
const vat = useVat(desk);
|
||||||
|
const otasEnabled = !vat?.arak.paused;
|
||||||
|
const otaSource = vat?.arak.ship;
|
||||||
|
const toggleOTAs = useKilnState((s) => s.toggleOTAs);
|
||||||
|
|
||||||
|
const toggleUpdates = useCallback((on: boolean) => toggleOTAs(desk, on), [desk, toggleOTAs]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="h3 mb-7">{charge?.title} Settings</h2>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Setting on={!!otasEnabled} toggle={toggleUpdates} name="Automatic Updates">
|
||||||
|
<p>Automatically download and apply updates to keep {charge?.title} up to date.</p>
|
||||||
|
{otaSource && (
|
||||||
|
<p>
|
||||||
|
OTA Source: <ShipName name={otaSource} className="font-semibold font-mono" />
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</Setting>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Setting } from '../../components/Setting';
|
import { Setting } from '../../components/Setting';
|
||||||
import { ShipName } from '../../components/ShipName';
|
|
||||||
import { useProtocolHandling, setLocalState } from '../../state/local';
|
import { useProtocolHandling, setLocalState } from '../../state/local';
|
||||||
|
|
||||||
export function InterfacePrefs() {
|
export function InterfacePrefs() {
|
||||||
@ -8,9 +7,13 @@ export function InterfacePrefs() {
|
|||||||
const toggleProtoHandling = async () => {
|
const toggleProtoHandling = async () => {
|
||||||
if (!protocolHandling && window?.navigator?.registerProtocolHandler) {
|
if (!protocolHandling && window?.navigator?.registerProtocolHandler) {
|
||||||
try {
|
try {
|
||||||
window.navigator.registerProtocolHandler('web+urbitgraph', '/apps/grid/perma?ext=%s', 'Urbit Links');
|
window.navigator.registerProtocolHandler(
|
||||||
setLocalState((s) => {
|
'web+urbitgraph',
|
||||||
s.protocolHandling = true;
|
'/apps/grid/perma?ext=%s',
|
||||||
|
'Urbit Links'
|
||||||
|
);
|
||||||
|
setLocalState((draft) => {
|
||||||
|
draft.protocolHandling = true;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -18,8 +21,8 @@ export function InterfacePrefs() {
|
|||||||
} else if (protocolHandling && window.navigator?.unregisterProtocolHandler) {
|
} else if (protocolHandling && window.navigator?.unregisterProtocolHandler) {
|
||||||
try {
|
try {
|
||||||
window.navigator.unregisterProtocolHandler('web+urbitgraph', '/apps/grid/perma?ext=%s');
|
window.navigator.unregisterProtocolHandler('web+urbitgraph', '/apps/grid/perma?ext=%s');
|
||||||
setLocalState((s) => {
|
setLocalState((draft) => {
|
||||||
s.protocolHandling = false;
|
draft.protocolHandling = false;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -33,8 +36,6 @@ export function InterfacePrefs() {
|
|||||||
<Setting on={protocolHandling} toggle={toggleProtoHandling} name="Handle Urbit links">
|
<Setting on={protocolHandling} toggle={toggleProtoHandling} name="Handle Urbit links">
|
||||||
<p>Automatically open urbit links with this urbit</p>
|
<p>Automatically open urbit links with this urbit</p>
|
||||||
</Setting>
|
</Setting>
|
||||||
|
|
||||||
<div className="space-y-3"> </div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import { setMentions } from '@urbit/api/dist';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Setting } from '../../components/Setting';
|
import { Setting } from '../../components/Setting';
|
||||||
|
import { pokeOptimisticallyN } from '../../state/base';
|
||||||
|
import { HarkState, reduceGraph, useHarkStore } from '../../state/hark';
|
||||||
import { useSettingsState, SettingsState } from '../../state/settings';
|
import { useSettingsState, SettingsState } from '../../state/settings';
|
||||||
import { usePreferencesStore } from './usePreferencesStore';
|
|
||||||
|
|
||||||
const selDnd = (s: SettingsState) => s.display.doNotDisturb;
|
const selDnd = (s: SettingsState) => s.display.doNotDisturb;
|
||||||
async function toggleDnd() {
|
async function toggleDnd() {
|
||||||
@ -9,9 +11,15 @@ async function toggleDnd() {
|
|||||||
await state.putEntry('display', 'doNotDisturb', !selDnd(state));
|
await state.putEntry('display', 'doNotDisturb', !selDnd(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selMentions = (s: HarkState) => s.notificationsGraphConfig.mentions;
|
||||||
|
async function toggleMentions() {
|
||||||
|
const state = useHarkStore.getState();
|
||||||
|
await pokeOptimisticallyN(useHarkStore, setMentions(!selMentions(state)), reduceGraph);
|
||||||
|
}
|
||||||
|
|
||||||
export const NotificationPrefs = () => {
|
export const NotificationPrefs = () => {
|
||||||
const { mentions, toggleMentions } = usePreferencesStore();
|
|
||||||
const doNotDisturb = useSettingsState(selDnd);
|
const doNotDisturb = useSettingsState(selDnd);
|
||||||
|
const mentions = useHarkStore(selMentions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -28,14 +36,7 @@ export const NotificationPrefs = () => {
|
|||||||
</p>
|
</p>
|
||||||
</Setting>
|
</Setting>
|
||||||
<Setting on={mentions} toggle={toggleMentions} name="Mentions">
|
<Setting on={mentions} toggle={toggleMentions} name="Mentions">
|
||||||
<p>
|
<p>Notify me if someone mentions my @p in a channel I've joined</p>
|
||||||
[PLACEHOLDER] Block visual desktop notifications whenever Urbit software produces an
|
|
||||||
in-Landscape notification badge.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Turning this "off" will prompt your browser to ask if you'd like to
|
|
||||||
enable notifications
|
|
||||||
</p>
|
|
||||||
</Setting>
|
</Setting>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -1,19 +1,30 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
import React, { ChangeEvent, FormEvent, useCallback, useEffect, useState } from 'react';
|
import React, { ChangeEvent, FormEvent, useCallback, useEffect, useState } from 'react';
|
||||||
import { Button } from '../../components/Button';
|
import { Button } from '../../components/Button';
|
||||||
import { Setting } from '../../components/Setting';
|
import { Setting } from '../../components/Setting';
|
||||||
import { ShipName } from '../../components/ShipName';
|
import { ShipName } from '../../components/ShipName';
|
||||||
import { Spinner } from '../../components/Spinner';
|
import { Spinner } from '../../components/Spinner';
|
||||||
import { useAsyncCall } from '../../logic/useAsyncCall';
|
import { useAsyncCall } from '../../logic/useAsyncCall';
|
||||||
import { usePreferencesStore } from './usePreferencesStore';
|
import useKilnState, { useVat } from '../../state/kiln';
|
||||||
|
|
||||||
export const SystemUpdatePrefs = () => {
|
export const SystemUpdatePrefs = () => {
|
||||||
const { otasEnabled, otaSource, toggleOTAs, setOTASource } = usePreferencesStore();
|
const { changeOTASource, toggleOTAs } = useKilnState((s) =>
|
||||||
const [source, setSource] = useState(otaSource);
|
_.pick(s, ['toggleOTAs', 'changeOTASource'])
|
||||||
|
);
|
||||||
|
const base = useVat('base');
|
||||||
|
const otasEnabled = base && !base.arak.paused;
|
||||||
|
const otaSource = base?.arak.ship;
|
||||||
|
|
||||||
|
const toggleBase = useCallback((on: boolean) => toggleOTAs('base', on), [toggleOTAs]);
|
||||||
|
|
||||||
|
const [source, setSource] = useState('');
|
||||||
const sourceDirty = source !== otaSource;
|
const sourceDirty = source !== otaSource;
|
||||||
const { status: sourceStatus, call: setOTA } = useAsyncCall(setOTASource);
|
const { status: sourceStatus, call: setOTA } = useAsyncCall(changeOTASource);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSource(otaSource);
|
if (otaSource) {
|
||||||
|
setSource(otaSource);
|
||||||
|
}
|
||||||
}, [otaSource]);
|
}, [otaSource]);
|
||||||
|
|
||||||
const handleSourceChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleSourceChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -34,11 +45,13 @@ export const SystemUpdatePrefs = () => {
|
|||||||
<>
|
<>
|
||||||
<h2 className="h3 mb-7">System Updates</h2>
|
<h2 className="h3 mb-7">System Updates</h2>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<Setting on={otasEnabled} toggle={toggleOTAs} name="Enable Automatic Urbit OTAs">
|
<Setting on={!!otasEnabled} toggle={toggleBase} name="Enable Automatic Urbit OTAs">
|
||||||
<p>Automatically download and apply system updates to keep your Urbit up to date.</p>
|
<p>Automatically download and apply system updates to keep your Urbit up to date.</p>
|
||||||
<p>
|
{otaSource && (
|
||||||
OTA Source: <ShipName name={otaSource} className="font-semibold font-mono" />
|
<p>
|
||||||
</p>
|
OTA Source: <ShipName name={otaSource} className="font-semibold font-mono" />
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</Setting>
|
</Setting>
|
||||||
<form className="inner-section relative" onSubmit={onSubmit}>
|
<form className="inner-section relative" onSubmit={onSubmit}>
|
||||||
<label htmlFor="ota-source" className="h4 mb-3">
|
<label htmlFor="ota-source" className="h4 mb-3">
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import create from 'zustand';
|
|
||||||
import { fakeRequest } from '../../state/util';
|
|
||||||
|
|
||||||
const useMockData = import.meta.env.MODE === 'mock';
|
|
||||||
|
|
||||||
interface PreferencesStore {
|
|
||||||
theme: 'light' | 'dark' | 'automatic';
|
|
||||||
currentTheme: 'light' | 'dark';
|
|
||||||
otasEnabled: boolean;
|
|
||||||
otaSource: string;
|
|
||||||
doNotDisturb: boolean;
|
|
||||||
mentions: boolean;
|
|
||||||
setOTASource: (source: string) => Promise<void>;
|
|
||||||
toggleOTAs: () => Promise<void>;
|
|
||||||
toggleDoNotDisturb: () => Promise<void>;
|
|
||||||
toggleMentions: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const usePreferencesStore = create<PreferencesStore>((set) => ({
|
|
||||||
theme: 'automatic',
|
|
||||||
currentTheme: 'light',
|
|
||||||
otasEnabled: true,
|
|
||||||
otaSource: useMockData ? '~sabbus' : '',
|
|
||||||
doNotDisturb: false,
|
|
||||||
mentions: true,
|
|
||||||
/**
|
|
||||||
* a lot of these are repetitive, we may do better with a map of settings
|
|
||||||
* and some generic way to update them through pokes. That way, we could
|
|
||||||
* just have toggleSetting(key) and run a similar op for all
|
|
||||||
*/
|
|
||||||
toggleOTAs: async () => {
|
|
||||||
if (useMockData) {
|
|
||||||
await fakeRequest({});
|
|
||||||
set((state) => ({ otasEnabled: !state.otasEnabled }));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setOTASource: async (source: string) => {
|
|
||||||
if (useMockData) {
|
|
||||||
await fakeRequest({});
|
|
||||||
set({ otaSource: source });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleDoNotDisturb: async () => {
|
|
||||||
if (useMockData) {
|
|
||||||
await fakeRequest({});
|
|
||||||
set((state) => ({ doNotDisturb: !state.doNotDisturb }));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleMentions: async () => {
|
|
||||||
if (useMockData) {
|
|
||||||
await fakeRequest({});
|
|
||||||
set((state) => ({ mentions: !state.mentions }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
@ -1,4 +1,5 @@
|
|||||||
import Urbit from '@urbit/http-api';
|
import Urbit from '@urbit/http-api';
|
||||||
|
import { useMockData } from './util';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@ -6,17 +7,18 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const api =
|
const api = useMockData
|
||||||
import.meta.env.MODE === 'mock'
|
? ({
|
||||||
? ({
|
poke: async () => {},
|
||||||
poke: async () => {},
|
subscribe: async () => {},
|
||||||
subscribe: async () => {},
|
subscribeOnce: async () => {},
|
||||||
subscribeOnce: async () => {},
|
ship: '',
|
||||||
ship: '',
|
scry: async () => {}
|
||||||
scry: async () => {}
|
} as unknown as Urbit)
|
||||||
} as unknown as Urbit)
|
: new Urbit('', '');
|
||||||
: new Urbit('', '');
|
if (useMockData) {
|
||||||
|
api.verbose = true;
|
||||||
api.ship = import.meta.env.MODE === 'mock' ? 'dopzod' : window.ship;
|
}
|
||||||
|
api.ship = useMockData ? 'dopzod' : window.ship;
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
@ -1,12 +1,57 @@
|
|||||||
import create from 'zustand';
|
import _ from 'lodash';
|
||||||
|
import { NotificationGraphConfig } from '@urbit/api';
|
||||||
import { Notification } from './hark-types';
|
import { Notification } from './hark-types';
|
||||||
import { mockNotification } from './mock-data';
|
import { mockNotification } from './mock-data';
|
||||||
import { useMockData } from './util';
|
import { useMockData } from './util';
|
||||||
|
import { BaseState, createState, createSubscription, reduceStateN } from './base';
|
||||||
|
|
||||||
interface HarkStore {
|
export interface HarkState {
|
||||||
notifications: Notification[];
|
notifications: Notification[];
|
||||||
|
notificationsGraphConfig: NotificationGraphConfig;
|
||||||
|
[ref: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useHarkStore = create<HarkStore>(() => ({
|
type BaseHarkState = HarkState & BaseState<HarkState>;
|
||||||
notifications: useMockData ? [mockNotification] : []
|
|
||||||
}));
|
function updateState(
|
||||||
|
key: string,
|
||||||
|
transform: (state: BaseHarkState, data: any) => void
|
||||||
|
): (json: any, state: BaseHarkState) => BaseHarkState {
|
||||||
|
return (json: any, state: BaseHarkState) => {
|
||||||
|
if (_.has(json, key)) {
|
||||||
|
transform(state, _.get(json, key, undefined));
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reduceGraph = [
|
||||||
|
updateState('initial', (draft, data) => {
|
||||||
|
draft.notificationsGraphConfig = data;
|
||||||
|
}),
|
||||||
|
updateState('set-mentions', (draft, data) => {
|
||||||
|
draft.notificationsGraphConfig.mentions = data;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
export const useHarkStore = createState<HarkState>(
|
||||||
|
'Hark',
|
||||||
|
() => ({
|
||||||
|
notifications: useMockData ? [mockNotification] : [],
|
||||||
|
notificationsGraphConfig: {
|
||||||
|
watchOnSelf: false,
|
||||||
|
mentions: false,
|
||||||
|
watching: []
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
(set, get) =>
|
||||||
|
createSubscription('hark-graph-hook', '/updates', (j) => {
|
||||||
|
const graphHookData = _.get(j, 'hark-graph-hook-update', false);
|
||||||
|
if (graphHookData) {
|
||||||
|
reduceStateN(get(), graphHookData, reduceGraph);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { getVats, Vats, scryLag, getBlockers, Vat } from '@urbit/api';
|
import { getVats, Vats, scryLag, getBlockers, Vat, kilnInstall } from '@urbit/api';
|
||||||
|
import { kilnPause, kilnResume } from '@urbit/api/hood';
|
||||||
import create from 'zustand';
|
import create from 'zustand';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
@ -12,6 +13,8 @@ interface KilnState {
|
|||||||
fetchVats: () => Promise<void>;
|
fetchVats: () => Promise<void>;
|
||||||
lag: boolean;
|
lag: boolean;
|
||||||
fetchLag: () => Promise<void>;
|
fetchLag: () => Promise<void>;
|
||||||
|
changeOTASource: (ship: string) => Promise<void>;
|
||||||
|
toggleOTAs: (desk: string, on: boolean) => Promise<void>;
|
||||||
set: (s: KilnState) => void;
|
set: (s: KilnState) => void;
|
||||||
}
|
}
|
||||||
const useKilnState = create<KilnState>((set) => ({
|
const useKilnState = create<KilnState>((set) => ({
|
||||||
@ -31,6 +34,39 @@ const useKilnState = create<KilnState>((set) => ({
|
|||||||
const lag = await api.scry<boolean>(scryLag);
|
const lag = await api.scry<boolean>(scryLag);
|
||||||
set({ lag });
|
set({ lag });
|
||||||
},
|
},
|
||||||
|
changeOTASource: async (ship: string) => {
|
||||||
|
if (useMockData) {
|
||||||
|
await fakeRequest('');
|
||||||
|
set(
|
||||||
|
produce((draft: KilnState) => {
|
||||||
|
draft.vats.base.arak.ship = ship;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await api.poke(kilnInstall(ship, '%kids', 'base'));
|
||||||
|
},
|
||||||
|
toggleOTAs: async (desk: string, on: boolean) => {
|
||||||
|
if (useMockData) {
|
||||||
|
await fakeRequest('');
|
||||||
|
set(
|
||||||
|
produce((draft: KilnState) => {
|
||||||
|
const { arak } = draft.vats[desk];
|
||||||
|
|
||||||
|
if (on) {
|
||||||
|
arak.paused = false;
|
||||||
|
} else {
|
||||||
|
arak.paused = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await api.poke(on ? kilnResume(desk) : kilnPause(desk));
|
||||||
|
},
|
||||||
set: produce(set)
|
set: produce(set)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import produce from 'immer';
|
|||||||
|
|
||||||
interface LocalState {
|
interface LocalState {
|
||||||
protocolHandling: boolean;
|
protocolHandling: boolean;
|
||||||
|
currentTheme: 'light' | 'dark';
|
||||||
set: (f: (s: LocalState) => void) => void;
|
set: (f: (s: LocalState) => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,6 +12,7 @@ export const useLocalState = create<LocalState>(
|
|||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
set: (f) => set(produce(get(), f)),
|
set: (f) => set(produce(get(), f)),
|
||||||
|
currentTheme: 'light',
|
||||||
protocolHandling: false
|
protocolHandling: false
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
@ -24,4 +26,9 @@ export function useProtocolHandling() {
|
|||||||
return useLocalState(selProtocolHandling);
|
return useLocalState(selProtocolHandling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selCurrentTheme = (s: LocalState) => s.currentTheme;
|
||||||
|
export function useCurrentTheme() {
|
||||||
|
return useLocalState(selCurrentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
export const setLocalState = (f: (s: LocalState) => void) => useLocalState.getState().set(f);
|
export const setLocalState = (f: (s: LocalState) => void) => useLocalState.getState().set(f);
|
||||||
|
@ -232,7 +232,8 @@ export const mockVat = (desk: string, blockers?: boolean): Vat => ({
|
|||||||
aeon: 3,
|
aeon: 3,
|
||||||
desk,
|
desk,
|
||||||
next: blockers ? [{ aeon: 3, weft: { name: 'zuse', kelvin: 419 } }] : [],
|
next: blockers ? [{ aeon: 3, weft: { name: 'zuse', kelvin: 419 } }] : [],
|
||||||
ship: '~zod'
|
ship: '~zod',
|
||||||
|
paused: false
|
||||||
},
|
},
|
||||||
hash: '0vh.lhfn6.julg1.fs52d.g2lqj.q5kp0.2o7j3.2bljl.jdm34.hd46v.9uv5v'
|
hash: '0vh.lhfn6.julg1.fs52d.g2lqj.q5kp0.2o7j3.2bljl.jdm34.hd46v.9uv5v'
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,7 @@ import api from './api';
|
|||||||
|
|
||||||
interface BaseSettingsState {
|
interface BaseSettingsState {
|
||||||
display: {
|
display: {
|
||||||
theme: 'light' | 'dark' | 'automatic';
|
theme: 'light' | 'dark' | 'auto';
|
||||||
doNotDisturb: boolean;
|
doNotDisturb: boolean;
|
||||||
};
|
};
|
||||||
putEntry: (bucket: string, key: string, value: Value) => Promise<void>;
|
putEntry: (bucket: string, key: string, value: Value) => Promise<void>;
|
||||||
@ -68,7 +68,7 @@ export const useSettingsState = createState<BaseSettingsState>(
|
|||||||
'Settings',
|
'Settings',
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
display: {
|
display: {
|
||||||
theme: 'automatic',
|
theme: 'auto',
|
||||||
doNotDisturb: true
|
doNotDisturb: true
|
||||||
},
|
},
|
||||||
loaded: false,
|
loaded: false,
|
||||||
@ -96,3 +96,8 @@ export const useSettingsState = createState<BaseSettingsState>(
|
|||||||
})
|
})
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const selTheme = (s: SettingsState) => s.display.theme;
|
||||||
|
export function useTheme() {
|
||||||
|
return useSettingsState(selTheme);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { darken, hsla, lighten, parseToHsla, readableColorIsBlack } from 'color2k';
|
import { darken, hsla, lighten, parseToHsla, readableColorIsBlack } from 'color2k';
|
||||||
import { usePreferencesStore } from '../nav/preferences/usePreferencesStore';
|
import { useCurrentTheme } from '../state/local';
|
||||||
|
|
||||||
function getDarkColor(color: string): string {
|
function getDarkColor(color: string): string {
|
||||||
const hslaColor = parseToHsla(color);
|
const hslaColor = parseToHsla(color);
|
||||||
@ -18,7 +18,7 @@ function getMenuColor(color: string, darkBg: boolean): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useTileColor = (color: string) => {
|
export const useTileColor = (color: string) => {
|
||||||
const theme = usePreferencesStore((s) => s.currentTheme);
|
const theme = useCurrentTheme();
|
||||||
const darkTheme = theme === 'dark';
|
const darkTheme = theme === 'dark';
|
||||||
const tileColor = darkTheme ? getDarkColor(color) : color;
|
const tileColor = darkTheme ? getDarkColor(color) : color;
|
||||||
const darkBg = !readableColorIsBlack(tileColor);
|
const darkBg = !readableColorIsBlack(tileColor);
|
||||||
|
@ -70,6 +70,22 @@ export function kilnBump(force = false, except = [] as string[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function kilnPause(desk: string) {
|
||||||
|
return {
|
||||||
|
app: 'hood',
|
||||||
|
mark: 'kiln-pause',
|
||||||
|
json: desk
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function kilnResume(desk: string) {
|
||||||
|
return {
|
||||||
|
app: 'hood',
|
||||||
|
mark: 'kiln-resume',
|
||||||
|
json: desk
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const scryLag: Scry = ({ app: 'hood', path: '/kiln/lag' });
|
export const scryLag: Scry = ({ app: 'hood', path: '/kiln/lag' });
|
||||||
|
|
||||||
export function getBlockers(vats: Vats): string[] {
|
export function getBlockers(vats: Vats): string[] {
|
||||||
|
@ -37,6 +37,7 @@ export interface Arak {
|
|||||||
aeon: number;
|
aeon: number;
|
||||||
next: Woof[];
|
next: Woof[];
|
||||||
rein: Rein;
|
rein: Rein;
|
||||||
|
paused: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,6 +139,10 @@ export interface Vat {
|
|||||||
* .^(@uv %cz /=desk=)
|
* .^(@uv %cz /=desk=)
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* True if desk is no longer syncing from upstream
|
||||||
|
*/
|
||||||
|
paused: boolean;
|
||||||
hash: string;
|
hash: string;
|
||||||
/**
|
/**
|
||||||
* Current revision
|
* Current revision
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An urbit style path, rendered as a Javascript string
|
* An urbit style path, rendered as a Javascript string
|
||||||
* @example
|
* @example
|
||||||
@ -28,7 +27,6 @@ export type Patp = string;
|
|||||||
*/
|
*/
|
||||||
export type PatpNoSig = string;
|
export type PatpNoSig = string;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of a clay mark, as a string
|
* The name of a clay mark, as a string
|
||||||
*
|
*
|
||||||
@ -115,7 +113,7 @@ export interface Thread<Action> {
|
|||||||
/**
|
/**
|
||||||
* Desk of thread
|
* Desk of thread
|
||||||
*/
|
*/
|
||||||
desk: string;
|
desk?: string;
|
||||||
/**
|
/**
|
||||||
* Data of the input vase
|
* Data of the input vase
|
||||||
*/
|
*/
|
||||||
@ -124,9 +122,6 @@ export interface Thread<Action> {
|
|||||||
|
|
||||||
export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete';
|
export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface PokeHandlers {
|
export interface PokeHandlers {
|
||||||
onSuccess?: () => void;
|
onSuccess?: () => void;
|
||||||
onError?: (e: any) => void;
|
onError?: (e: any) => void;
|
||||||
@ -182,14 +177,13 @@ export interface headers {
|
|||||||
Cookie?: string;
|
Cookie?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface CustomEventHandler {
|
export interface CustomEventHandler {
|
||||||
(data: any, response: string): void;
|
(data: any, response: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SSEOptions {
|
export interface SSEOptions {
|
||||||
headers?: {
|
headers?: {
|
||||||
Cookie?: string
|
Cookie?: string;
|
||||||
};
|
};
|
||||||
withCredentials?: boolean;
|
withCredentials?: boolean;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user