improve bookmarks page layout
This commit is contained in:
@@ -34,7 +34,9 @@ interface BookmarkPageState {
|
|||||||
bookmarkToBeDeleted: LinkBookmark | null
|
bookmarkToBeDeleted: LinkBookmark | null
|
||||||
layoutMode: LayoutMode
|
layoutMode: LayoutMode
|
||||||
activeDialog: ActiveDialog
|
activeDialog: ActiveDialog
|
||||||
|
actionBarHeight: number
|
||||||
|
|
||||||
|
setActionBarHeight: (height: number) => void
|
||||||
setActiveDialog: (dialog: ActiveDialog) => void
|
setActiveDialog: (dialog: ActiveDialog) => void
|
||||||
setBookmarkItemExpanded: (isExpanded: boolean) => void
|
setBookmarkItemExpanded: (isExpanded: boolean) => void
|
||||||
setBookmarkPreviewOpened: (isOpened: boolean) => void
|
setBookmarkPreviewOpened: (isOpened: boolean) => void
|
||||||
@@ -54,6 +56,11 @@ const useBookmarkPageStore = create<BookmarkPageState>()((set, get) => ({
|
|||||||
bookmarkToBeDeleted: null,
|
bookmarkToBeDeleted: null,
|
||||||
layoutMode: LAYOUT_MODE.popup,
|
layoutMode: LAYOUT_MODE.popup,
|
||||||
activeDialog: ActiveDialog.None,
|
activeDialog: ActiveDialog.None,
|
||||||
|
actionBarHeight: 0,
|
||||||
|
|
||||||
|
setActionBarHeight(height: number) {
|
||||||
|
set({ actionBarHeight: height })
|
||||||
|
},
|
||||||
|
|
||||||
setActiveDialog(dialog: ActiveDialog) {
|
setActiveDialog(dialog: ActiveDialog) {
|
||||||
set({ activeDialog: dialog })
|
set({ activeDialog: dialog })
|
||||||
@@ -77,16 +84,21 @@ const useBookmarkPageStore = create<BookmarkPageState>()((set, get) => ({
|
|||||||
|
|
||||||
reconcileSelection(bookmarks: LinkBookmark[]) {
|
reconcileSelection(bookmarks: LinkBookmark[]) {
|
||||||
const { selectedBookmarkId, selectedBookmarkIndex } = get()
|
const { selectedBookmarkId, selectedBookmarkIndex } = get()
|
||||||
const newIndex = bookmarks.findIndex((bookmark) => bookmark.id === selectedBookmarkId)
|
|
||||||
if (newIndex !== selectedBookmarkIndex) {
|
if (!selectedBookmarkId) {
|
||||||
if (newIndex >= 0) {
|
set({ selectedBookmarkId: bookmarks[selectedBookmarkIndex].id })
|
||||||
set({ selectedBookmarkIndex: newIndex })
|
} else {
|
||||||
} else if (selectedBookmarkIndex >= bookmarks.length - 1) {
|
const newIndex = bookmarks.findIndex((bookmark) => bookmark.id === selectedBookmarkId)
|
||||||
set({ selectedBookmarkIndex: bookmarks.length - 1 })
|
if (newIndex !== selectedBookmarkIndex) {
|
||||||
} else if (selectedBookmarkIndex === 0) {
|
if (newIndex >= 0) {
|
||||||
set({ selectedBookmarkIndex: 0 })
|
set({ selectedBookmarkIndex: newIndex })
|
||||||
} else {
|
} else if (selectedBookmarkIndex >= bookmarks.length - 1) {
|
||||||
set({ selectedBookmarkIndex: selectedBookmarkIndex + 1 })
|
set({ selectedBookmarkIndex: bookmarks.length - 1 })
|
||||||
|
} else if (selectedBookmarkIndex === 0) {
|
||||||
|
set({ selectedBookmarkIndex: 0 })
|
||||||
|
} else {
|
||||||
|
set({ selectedBookmarkIndex: selectedBookmarkIndex + 1 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -121,15 +133,7 @@ function Page() {
|
|||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Main>
|
<Main>
|
||||||
<div className="flex flex-col md:flex-row justify-center py-16 lg:py-32">
|
<BookmarkListPane />
|
||||||
<header className="mb-4 md:mb-0 md:mr-16 text-start">
|
|
||||||
<h1 className="font-bold text-start">
|
|
||||||
<span className="invisible md:hidden">> </span>
|
|
||||||
YOUR BOOKMARKS
|
|
||||||
</h1>
|
|
||||||
</header>
|
|
||||||
<BookmarkListSection />
|
|
||||||
</div>
|
|
||||||
<BookmarkPreview />
|
<BookmarkPreview />
|
||||||
<ActionBar />
|
<ActionBar />
|
||||||
</Main>
|
</Main>
|
||||||
@@ -145,8 +149,8 @@ function Main({ children }: React.PropsWithChildren) {
|
|||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"px-4 lg:px-8 2xl:px-0 grid flex justify-center relative w-full",
|
"grid flex justify-center relative w-full",
|
||||||
isPreviewOpened && layoutMode === LAYOUT_MODE.sideBySide ? "grid-cols-2" : "grid-cols-1",
|
isPreviewOpened && layoutMode === LAYOUT_MODE.sideBySide ? "grid-cols-3" : "grid-cols-1",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -154,6 +158,28 @@ function Main({ children }: React.PropsWithChildren) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BookmarkListPane() {
|
||||||
|
const isBookmarkPreviewOpened = useBookmarkPageStore((state) => state.isBookmarkPreviewOpened)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx("flex flex-col py-16", { "md:flex-row lg:py-32 justify-center ": !isBookmarkPreviewOpened })}>
|
||||||
|
<header className="mb-4 md:mb-0 md:mr-16 text-start">
|
||||||
|
<h1 className={clsx("font-bold text-start", { "mb-4": isBookmarkPreviewOpened })}>
|
||||||
|
<span
|
||||||
|
className={clsx("invisible", {
|
||||||
|
"md:hidden": !isBookmarkPreviewOpened,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
YOUR BOOKMARKS
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<BookmarkListSection />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function PageDialog() {
|
function PageDialog() {
|
||||||
const dialog = useBookmarkPageStore((state) => state.activeDialog)
|
const dialog = useBookmarkPageStore((state) => state.activeDialog)
|
||||||
switch (dialog) {
|
switch (dialog) {
|
||||||
@@ -385,42 +411,57 @@ function BookmarkList({ bookmarks }: { bookmarks: LinkBookmark[] }) {
|
|||||||
reconcileSelection(bookmarks)
|
reconcileSelection(bookmarks)
|
||||||
}, [bookmarks, reconcileSelection])
|
}, [bookmarks, reconcileSelection])
|
||||||
|
|
||||||
useEffect(() => {
|
useMnemonics(
|
||||||
function onKeyDown(event: KeyboardEvent) {
|
{
|
||||||
const state = useBookmarkPageStore.getState()
|
j: selectNextItem,
|
||||||
|
ArrowDown: selectNextItem,
|
||||||
|
|
||||||
switch (event.key) {
|
k: selectPrevItem,
|
||||||
case "ArrowDown": {
|
ArrowUp: selectPrevItem,
|
||||||
const nextIndex = state.selectedBookmarkIndex + 1
|
|
||||||
if (nextIndex < bookmarks.length) {
|
h: collapseItem,
|
||||||
state.selectBookmark(bookmarks[nextIndex], nextIndex)
|
ArrowLeft: collapseItem,
|
||||||
}
|
|
||||||
break
|
l: expandItem,
|
||||||
}
|
ArrowRight: expandItem,
|
||||||
case "ArrowUp": {
|
|
||||||
const prevIndex = state.selectedBookmarkIndex - 1
|
Enter: () => {
|
||||||
if (prevIndex >= 0) {
|
const state = useBookmarkPageStore.getState()
|
||||||
state.selectBookmark(bookmarks[prevIndex], prevIndex)
|
expandItem()
|
||||||
}
|
state.setBookmarkPreviewOpened(true)
|
||||||
break
|
},
|
||||||
}
|
},
|
||||||
case "ArrowLeft":
|
{
|
||||||
state.setBookmarkItemExpanded(false)
|
ignore: useCallback(() => useBookmarkPageStore.getState().activeDialog !== ActiveDialog.None, []),
|
||||||
break
|
},
|
||||||
case "ArrowRight":
|
)
|
||||||
state.setBookmarkItemExpanded(true)
|
|
||||||
break
|
function selectPrevItem() {
|
||||||
default:
|
const state = useBookmarkPageStore.getState()
|
||||||
break
|
const prevIndex = state.selectedBookmarkIndex - 1
|
||||||
}
|
if (prevIndex >= 0) {
|
||||||
|
state.selectBookmark(bookmarks[prevIndex], prevIndex)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener("keydown", onKeyDown)
|
function selectNextItem() {
|
||||||
|
const state = useBookmarkPageStore.getState()
|
||||||
return () => {
|
const nextIndex = state.selectedBookmarkIndex + 1
|
||||||
window.removeEventListener("keydown", onKeyDown)
|
if (nextIndex < bookmarks.length) {
|
||||||
|
state.selectBookmark(bookmarks[nextIndex], nextIndex)
|
||||||
}
|
}
|
||||||
}, [bookmarks])
|
}
|
||||||
|
|
||||||
|
function expandItem() {
|
||||||
|
const state = useBookmarkPageStore.getState()
|
||||||
|
state.setBookmarkItemExpanded(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapseItem() {
|
||||||
|
const state = useBookmarkPageStore.getState()
|
||||||
|
state.setBookmarkItemExpanded(false)
|
||||||
|
state.setBookmarkPreviewOpened(false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col container max-w-2xl -mt-2">
|
<div className="flex flex-col container max-w-2xl -mt-2">
|
||||||
@@ -444,7 +485,7 @@ function BookmarkPreview() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"h-screen flex justify-center items-center border-l border-stone-700 dark:border-stone-300 flex dark:bg-stone-900",
|
"h-screen col-span-2 flex justify-center items-center border-l border-stone-700 dark:border-stone-300 flex dark:bg-stone-900",
|
||||||
{
|
{
|
||||||
"absolute inset-0 border-l-0": layoutMode === LAYOUT_MODE.popup,
|
"absolute inset-0 border-l-0": layoutMode === LAYOUT_MODE.popup,
|
||||||
},
|
},
|
||||||
@@ -457,6 +498,7 @@ function BookmarkPreview() {
|
|||||||
|
|
||||||
function BookmarkPreviewFrame() {
|
function BookmarkPreviewFrame() {
|
||||||
const selectedBookmarkId = useBookmarkPageStore((state) => state.selectedBookmarkId)
|
const selectedBookmarkId = useBookmarkPageStore((state) => state.selectedBookmarkId)
|
||||||
|
const actionBarHeight = useBookmarkPageStore((state) => state.actionBarHeight)
|
||||||
const { data, status } = useAuthenticatedQuery(["bookmarks", selectedBookmarkId], () =>
|
const { data, status } = useAuthenticatedQuery(["bookmarks", selectedBookmarkId], () =>
|
||||||
fetchApi(`/bookmark/${selectedBookmarkId}`, {
|
fetchApi(`/bookmark/${selectedBookmarkId}`, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -473,7 +515,13 @@ function BookmarkPreviewFrame() {
|
|||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
case "success":
|
case "success":
|
||||||
return <iframe className="bg-stone-200 dark:bg-stone-900 w-full h-full pb-20" srcDoc={data} />
|
return (
|
||||||
|
<iframe
|
||||||
|
className="prose bg-stone-200 dark:bg-stone-900 w-full h-full"
|
||||||
|
style={{ paddingBottom: actionBarHeight }}
|
||||||
|
srcDoc={data}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
@@ -513,7 +561,6 @@ function BookmarkListItem({ bookmark, index }: { bookmark: LinkBookmark; index:
|
|||||||
function expandOrOpenPreview() {
|
function expandOrOpenPreview() {
|
||||||
setBookmarkItemExpanded(true)
|
setBookmarkItemExpanded(true)
|
||||||
if (useBookmarkPageStore.getState().layoutMode === LAYOUT_MODE.sideBySide) {
|
if (useBookmarkPageStore.getState().layoutMode === LAYOUT_MODE.sideBySide) {
|
||||||
console.log(useBookmarkPageStore.getState().layoutMode)
|
|
||||||
setBookmarkPreviewOpened(true)
|
setBookmarkPreviewOpened(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,6 +675,10 @@ function OpenBookmarkPreviewButton() {
|
|||||||
|
|
||||||
function ActionBar() {
|
function ActionBar() {
|
||||||
const setActiveDialog = useBookmarkPageStore((state) => state.setActiveDialog)
|
const setActiveDialog = useBookmarkPageStore((state) => state.setActiveDialog)
|
||||||
|
const setActionBarHeight = useBookmarkPageStore((state) => state.setActionBarHeight)
|
||||||
|
const layoutMode = useBookmarkPageStore((state) => state.layoutMode)
|
||||||
|
const isBookmarkPreviewOpened = useBookmarkPageStore((state) => state.isBookmarkPreviewOpened)
|
||||||
|
const setBookmarkPreviewOpened = useBookmarkPageStore((state) => state.setBookmarkPreviewOpened)
|
||||||
|
|
||||||
useMnemonics(
|
useMnemonics(
|
||||||
{
|
{
|
||||||
@@ -640,15 +691,32 @@ function ActionBar() {
|
|||||||
setActiveDialog(ActiveDialog.AddBookmark)
|
setActiveDialog(ActiveDialog.AddBookmark)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closePreview() {
|
||||||
|
setBookmarkPreviewOpened(false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed z-10 bottom-0 left-0 right-0 bg-stone-200 dark:bg-stone-900 border-t-1 flex flex-row justify-center py-4 space-x-4">
|
<div
|
||||||
<Button onClick={addBookmark}>
|
ref={(el) => {
|
||||||
<span className="underline">A</span>DD
|
if (el) {
|
||||||
</Button>
|
setActionBarHeight(el.clientHeight)
|
||||||
<Button>
|
}
|
||||||
<span className="underline">S</span>EARCH
|
}}
|
||||||
</Button>
|
className="fixed z-10 bottom-0 left-0 right-0 bg-stone-200 dark:bg-stone-900 border-t-1 flex flex-row justify-center py-4 space-x-4"
|
||||||
<LogOutButton />
|
>
|
||||||
|
{layoutMode === LAYOUT_MODE.popup && isBookmarkPreviewOpened ? (
|
||||||
|
<Button onClick={closePreview}>CLOSE</Button>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Button onClick={addBookmark}>
|
||||||
|
<span className="underline">A</span>DD
|
||||||
|
</Button>
|
||||||
|
<Button>
|
||||||
|
<span className="underline">S</span>EARCH
|
||||||
|
</Button>
|
||||||
|
<LogOutButton />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ function useMnemonics(
|
|||||||
) {
|
) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onKeyDown(event: KeyboardEvent) {
|
function onKeyDown(event: KeyboardEvent) {
|
||||||
|
console.log(event.key)
|
||||||
if (!ignore(event)) {
|
if (!ignore(event)) {
|
||||||
mnemonicMap[event.key]?.(event)
|
mnemonicMap[event.key]?.(event)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user