1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

Добавили заметки в сайдбар (#126)

* added notes sidebar

* added note dropping and editing

* added sidebar navigation

* handling sidebarchanges over time

* using router back for closing sidebar

* fixed tripping inside single sidebar

* added superpowers toggle to sidebar

* user button opens sidebar now

* added profile cover for profile sidebar

* removed profile sidebar completely

* ran prettier over project

* added note not found error literal
This commit is contained in:
muerwre 2022-08-12 14:07:19 +07:00 committed by GitHub
parent fe3db608d6
commit 5d34090238
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 1241 additions and 664 deletions

View file

@ -9,22 +9,20 @@ import { stripHTMLTags } from '~/utils/stripHTMLTags';
export const formatTextSanitizeYoutube = (text: string): string =>
text.replace(
/(https?:\/\/(www\.)?(youtube\.com|youtu\.be)\/(watch)?(\?v=)?[\w\-&=]+)/gim,
'\n$1\n'
'\n$1\n',
);
/**
* Removes HTML tags
*/
export const formatTextSanitizeTags = (text: string): string => stripHTMLTags(text);
export const formatTextSanitizeTags = (text: string): string =>
stripHTMLTags(text);
/**
* Returns clickable usernames
*/
export const formatTextClickableUsernames = (text: string): string =>
text.replace(
/~([\wа-яА-Я-]+)/giu,
`<span class="username" onClick="window.postMessage({ type: '${EventMessageType.OpenProfile}', username: '$1'});">~$1</span>`
);
text.replace(/~([\wа-яА-Я-]+)/giu, `<span class="username">~$1</span>`);
/**
* Makes gray comments
@ -41,10 +39,13 @@ export const formatTextComments = (text: string): string =>
*/
export const formatTextTodos = (text: string): string =>
text
.replace(/\/\/\s*(todo|туду):?\s*([^\n]+)/gim, '// <span class="todo">$1</span> $2')
.replace(
/\/\/\s*(todo|туду):?\s*([^\n]+)/gim,
'// <span class="todo">$1</span> $2',
)
.replace(
/\/\/\s*(done|сделано|сделал|готово|fixed|пофикшено|фиксед):?\s*([^\n]+)/gim,
'// <span class="done">$1</span> $2'
'// <span class="done">$1</span> $2',
);
/**
@ -56,7 +57,8 @@ export const formatExclamations = (text: string): string =>
/**
* Replaces -- with dash
*/
export const formatTextDash = (text: string): string => text.replace(' -- ', ' — ');
export const formatTextDash = (text: string): string =>
text.replace(' -- ', ' — ');
/**
* Formats with markdown

View file

@ -0,0 +1,21 @@
import { createContext, FC, useContext } from 'react';
import { useNotes } from '~/hooks/notes/useNotes';
const NoteContext = createContext<ReturnType<typeof useNotes>>({
notes: [],
hasMore: false,
loadMore: async () => Promise.resolve(undefined),
isLoading: false,
create: () => Promise.resolve(),
remove: () => Promise.resolve(),
update: (id: number, text: string) => Promise.resolve(),
});
export const NoteProvider: FC = ({ children }) => {
const notes = useNotes('');
return <NoteContext.Provider value={notes}>{children}</NoteContext.Provider>;
};
export const useNotesContext = () => useContext(NoteContext);

View file

@ -1,78 +1,98 @@
import { Context, createContext, createElement, FunctionComponent, PropsWithChildren, useCallback, useContext, useMemo } from 'react';
import {
Context,
createContext,
createElement,
PropsWithChildren,
useCallback,
useContext,
useMemo,
} from 'react';
import { useRouter } from 'next/router';
import { has } from 'ramda';
import { has, omit } from 'ramda';
import { ModalWrapper } from '~/components/dialogs/ModalWrapper';
import { sidebarComponents, SidebarName } from '~/constants/sidebar';
import { DialogComponentProps } from '~/types/modal';
import { SidebarName } from '~/constants/sidebar';
import { sidebarComponents } from '~/constants/sidebar/components';
import { SidebarComponent, SidebarProps } from '~/types/sidebar';
type ContextValue = typeof SidebarContext extends Context<infer U> ? U : never;
type Name = keyof typeof sidebarComponents;
// TODO: use it to store props for sidebar
type Props<T extends Name> = typeof sidebarComponents[T] extends FunctionComponent<infer U>
? U extends DialogComponentProps ? Omit<U, 'onRequestClose'> : U
: {};
const SidebarContext = createContext({
current: undefined as SidebarName | undefined,
open: <T extends Name>(name: T) => {},
close: () => {},
open: <T extends SidebarComponent>(name: T, props: SidebarProps<T>) => {},
close: () => {},
});
export const SidebarProvider = <T extends Name>({ children }: PropsWithChildren<{}>) => {
export const SidebarProvider = <T extends SidebarComponent>({
children,
}: PropsWithChildren<{}>) => {
const router = useRouter();
const current = useMemo(() => {
const val = router.query.sidebar as SidebarName | undefined
const val = router.query.sidebar as SidebarName | undefined;
return val && has(val, sidebarComponents) ? val : undefined;
}, [router]);
const open = useCallback(
<T extends Name>(name: T) => {
<T extends SidebarComponent>(name: T, props: SidebarProps<T>) => {
const [path] = router.asPath.split('?');
void router.push(path + '?sidebar=' + name, path + '?sidebar=' + name, {
const query = Object.entries(props as {})
.filter(([, val]) => val)
.map(([name, val]) => `${name}=${val}`)
.join('&');
const url = path + '?sidebar=' + name + (query && `&${query}`);
// don't store history inside the same sidebar
if (router.query?.sidebar === name) {
void router.replace(url, url, {
shallow: true,
scroll: false,
});
return;
}
void router.push(url, url, {
shallow: true,
scroll: false,
});
},
[router]
[router],
);
const close = useCallback(
() => {
const [path] = router.asPath.split('?');
const close = useCallback(() => {
const [path] = router.asPath.split('?');
console.log('trying to close');
void router.replace(path, path, {
shallow: true,
scroll: false,
});
}, [router]);
void router.replace(path, path, {
shallow: true,
scroll: false,
});
},
[router]
const value = useMemo<ContextValue>(
() => ({
current,
open,
close,
}),
[current, open, close],
);
const value = useMemo<ContextValue>(() => ({
current,
open,
close,
}), [current, open, close]);
return (
<SidebarContext.Provider value={value}>
{children}
{current &&
{current && (
<ModalWrapper onOverlayClick={close}>
{createElement(
sidebarComponents[current],
{ onRequestClose: close } as any
)}
{createElement(sidebarComponents[current], {
onRequestClose: close,
openSidebar: open,
...omit(['sidebar'], router.query),
} as any)}
</ModalWrapper>
}
)}
</SidebarContext.Provider>
);
}
};
export const useSidebar = () => useContext(SidebarContext);

View file

@ -1,9 +0,0 @@
import { EventMessageType } from '~/constants/events';
export const openUserProfile = (username?: string) => {
if (!username) {
return;
}
window.postMessage({ type: EventMessageType.OpenProfile, username }, '*');
};