prefs: hooking up mentions pref

This commit is contained in:
Hunter Miller 2021-09-14 10:50:39 -05:00
parent 50c42c3558
commit 8dd9113843
6 changed files with 80 additions and 21 deletions

View File

@ -8,6 +8,7 @@ import useKilnState from './state/kiln';
import { usePreferencesStore } from './nav/preferences/usePreferencesStore';
import useContactState from './state/contact';
import api from './state/api';
import { useHarkStore } from './state/hark';
const AppRoutes = () => {
const { push } = useHistory();
@ -46,6 +47,7 @@ const AppRoutes = () => {
fetchVats();
fetchLag();
useContactState.getState().initialize(api);
useHarkStore.getState().initialize(api);
Mousetrap.bind(['command+/', 'ctrl+/'], () => {
push('/leap/search');

View File

@ -20,12 +20,12 @@ export const Setting: FC<SettingsProps> = ({ name, on, toggle, className, childr
<h3 id={id} className="flex items-center h4 mb-2">
{name} {status === 'loading' && <Spinner className="ml-2" />}
</h3>
<div className="flex items-center space-x-2">
<div className="flex space-x-2">
<Toggle
aria-labelledby={id}
pressed={on}
onPressedChange={call}
className="text-blue-400"
className="flex-none self-start text-blue-400"
/>
<div className="flex-1 space-y-6">{children}</div>
</div>

View File

@ -6,12 +6,13 @@ import type * as Polymorphic from '@radix-ui/react-polymorphic';
type ToggleComponent = Polymorphic.ForwardRefComponent<
Polymorphic.IntrinsicElement<typeof RadixToggle.Root>,
Polymorphic.OwnProps<typeof RadixToggle.Root> & {
toggleClass?: string;
knobClass?: string;
}
>;
export const Toggle = React.forwardRef(
({ defaultPressed, pressed, onPressedChange, disabled, className }, ref) => {
({ defaultPressed, pressed, onPressedChange, disabled, className, toggleClass }, ref) => {
const [on, setOn] = useState(defaultPressed);
const isControlled = !!onPressedChange;
const proxyPressed = isControlled ? pressed : on;
@ -20,14 +21,14 @@ export const Toggle = React.forwardRef(
return (
<RadixToggle.Root
className="default-ring rounded-full"
className={classNames('default-ring rounded-full', className)}
pressed={proxyPressed}
onPressedChange={proxyOnPressedChange}
disabled={disabled}
ref={ref}
>
<svg
className={classNames('w-12 h-8', className)}
className={classNames('w-12 h-8', toggleClass)}
viewBox="0 0 48 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"

View File

@ -1,6 +1,5 @@
import React from 'react';
import { Setting } from '../../components/Setting';
import { ShipName } from '../../components/ShipName';
import { useProtocolHandling, setLocalState } from '../../state/local';
export function InterfacePrefs() {
@ -8,9 +7,13 @@ export function InterfacePrefs() {
const toggleProtoHandling = async () => {
if (!protocolHandling && window?.navigator?.registerProtocolHandler) {
try {
window.navigator.registerProtocolHandler('web+urbitgraph', '/apps/grid/perma?ext=%s', 'Urbit Links');
setLocalState((s) => {
s.protocolHandling = true;
window.navigator.registerProtocolHandler(
'web+urbitgraph',
'/apps/grid/perma?ext=%s',
'Urbit Links'
);
setLocalState((draft) => {
draft.protocolHandling = true;
});
} catch (e) {
console.error(e);
@ -18,8 +21,8 @@ export function InterfacePrefs() {
} else if (protocolHandling && window.navigator?.unregisterProtocolHandler) {
try {
window.navigator.unregisterProtocolHandler('web+urbitgraph', '/apps/grid/perma?ext=%s');
setLocalState((s) => {
s.protocolHandling = false;
setLocalState((draft) => {
draft.protocolHandling = false;
});
} catch (e) {
console.error(e);
@ -31,10 +34,10 @@ export function InterfacePrefs() {
<>
<h2 className="h3 mb-7">Interface Settings</h2>
<Setting on={protocolHandling} toggle={toggleProtoHandling} name="Handle Urbit links">
<p>Automatically open urbit links with this urbit</p>
<p className="flex flex-col justify-center h-full">
Automatically open urbit links with this urbit
</p>
</Setting>
<div className="space-y-3"> </div>
</>
);
}

View File

@ -1,7 +1,9 @@
import { setMentions } from '@urbit/api/dist';
import React from 'react';
import { Setting } from '../../components/Setting';
import { pokeOptimisticallyN } from '../../state/base';
import { HarkState, reduceGraph, useHarkStore } from '../../state/hark';
import { useSettingsState, SettingsState } from '../../state/settings';
import { usePreferencesStore } from './usePreferencesStore';
const selDnd = (s: SettingsState) => s.display.doNotDisturb;
async function toggleDnd() {
@ -9,9 +11,15 @@ async function toggleDnd() {
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 = () => {
const { mentions, toggleMentions } = usePreferencesStore();
const doNotDisturb = useSettingsState(selDnd);
const mentions = useHarkStore(selMentions);
return (
<>

View File

@ -1,12 +1,57 @@
import create from 'zustand';
import _ from 'lodash';
import { NotificationGraphConfig } from '@urbit/api';
import { Notification } from './hark-types';
import { mockNotification } from './mock-data';
import { useMockData } from './util';
import { BaseState, createState, createSubscription, reduceStateN } from './base';
interface HarkStore {
export interface HarkState {
notifications: Notification[];
notificationsGraphConfig: NotificationGraphConfig;
[ref: string]: unknown;
}
export const useHarkStore = create<HarkStore>(() => ({
notifications: useMockData ? [mockNotification] : []
}));
type BaseHarkState = HarkState & BaseState<HarkState>;
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);
}
})
]
);