feat: add header in notebook view

This commit is contained in:
thecodrr
2021-12-02 12:12:42 +05:00
parent 04cfb6ff6c
commit 4b6b10794c
5 changed files with 133 additions and 67 deletions

View File

@@ -123,6 +123,8 @@ import {
mdiFirefox, mdiFirefox,
mdiAppleSafari, mdiAppleSafari,
mdiBugOutline, mdiBugOutline,
mdiLinkVariant,
mdiLinkVariantOff,
} from "@mdi/js"; } from "@mdi/js";
import { useTheme } from "emotion-theming"; import { useTheme } from "emotion-theming";
import { AnimatedFlex } from "../animated"; import { AnimatedFlex } from "../animated";
@@ -149,6 +151,7 @@ function createIcon(name, rotate = false) {
const [isHovering, setIsHovering] = useState(); const [isHovering, setIsHovering] = useState();
return ( return (
<AnimatedFlex <AnimatedFlex
flexShrink={0}
id={props.id} id={props.id}
title={props.title} title={props.title}
variant={props.variant} variant={props.variant}
@@ -312,3 +315,5 @@ export const Anonymous = createIcon(mdiIncognito);
export const CloudLock = createIcon(mdiCloudLockOutline); export const CloudLock = createIcon(mdiCloudLockOutline);
export const Timebomb = createIcon(mdiBomb); export const Timebomb = createIcon(mdiBomb);
export const Issue = createIcon(mdiBugOutline); export const Issue = createIcon(mdiBugOutline);
export const ShortcutLink = createIcon(mdiLinkVariant);
export const RemoveShortcutLink = createIcon(mdiLinkVariantOff);

View File

@@ -12,7 +12,7 @@ import Announcements from "../announcements";
import useAnnouncements from "../../utils/use-announcements"; import useAnnouncements from "../../utils/use-announcements";
function ListContainer(props) { function ListContainer(props) {
const { type, groupType, items, context, refresh } = props; const { type, groupType, items, context, refresh, header } = props;
const [announcements, removeAnnouncement] = useAnnouncements(); const [announcements, removeAnnouncement] = useAnnouncements();
const profile = useMemo(() => ListProfiles[type], [type]); const profile = useMemo(() => ListProfiles[type], [type]);
const shouldSelectAll = useSelectionStore((store) => store.shouldSelectAll); const shouldSelectAll = useSelectionStore((store) => store.shouldSelectAll);
@@ -27,9 +27,12 @@ function ListContainer(props) {
return ( return (
<Flex variant="columnFill"> <Flex variant="columnFill">
{!props.items.length && props.placeholder ? ( {!props.items.length && props.placeholder ? (
<>
{header}
<Flex variant="columnCenterFill"> <Flex variant="columnCenterFill">
{props.isLoading ? <Icon.Loading rotate /> : <props.placeholder />} {props.isLoading ? <Icon.Loading rotate /> : <props.placeholder />}
</Flex> </Flex>
</>
) : ( ) : (
<> <>
<Flex variant="columnFill" data-test-id="note-list"> <Flex variant="columnFill" data-test-id="note-list">
@@ -43,7 +46,9 @@ function ListContainer(props) {
components={{ components={{
Scroller: CustomScrollbarsVirtualList, Scroller: CustomScrollbarsVirtualList,
Header: () => Header: () =>
announcements.length ? ( header ? (
header
) : announcements.length ? (
<Announcements <Announcements
announcements={announcements} announcements={announcements}
removeAnnouncement={removeAnnouncement} removeAnnouncement={removeAnnouncement}

View File

@@ -48,7 +48,7 @@ function Header(props) {
(store) => store.toggleSelectionMode (store) => store.toggleSelectionMode
); );
if (!title && !subtitle) return null; // if (!subtitle) return null;
return ( return (
<Flex mx={2} flexDirection="column" justifyContent="center"> <Flex mx={2} flexDirection="column" justifyContent="center">
<Flex alignItems="center" justifyContent="space-between"> <Flex alignItems="center" justifyContent="space-between">
@@ -75,11 +75,14 @@ function Header(props) {
size={30} size={30}
/> />
)} )}
{title && (
<RouteTitle <RouteTitle
subtitle={subtitle}
title={title} title={title}
isEditable={isEditable} isEditable={isEditable}
onChange={onChange} onChange={onChange}
/> />
)}
</Flex> </Flex>
<SelectionOptions options={SELECTION_OPTIONS_MAP[type]} /> <SelectionOptions options={SELECTION_OPTIONS_MAP[type]} />
{!isSelectionMode && ( {!isSelectionMode && (
@@ -111,18 +114,6 @@ function Header(props) {
</Flex> </Flex>
)} )}
</Flex> </Flex>
{subtitle && (
<Text
variant="title"
color="primary"
sx={{
marginBottom: 2,
cursor: "normal",
}}
>
{subtitle}
</Text>
)}
{isSelectionMode && ( {isSelectionMode && (
<Flex <Flex
mb={2} mb={2}
@@ -165,7 +156,7 @@ function SelectionOptions(props) {
); );
} }
function RouteTitle({ title, isEditable, onChange }) { function RouteTitle({ title, subtitle, isEditable, onChange }) {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const ref = useRef(); const ref = useRef();
useEffect(() => { useEffect(() => {
@@ -173,9 +164,11 @@ function RouteTitle({ title, isEditable, onChange }) {
}, [title]); }, [title]);
return ( return (
<Flex flexDirection="column">
{subtitle && <Text variant="subBody">{subtitle}</Text>}
<Input <Input
ref={ref} ref={ref}
variant="heading" variant="clean"
data-test-id="routeHeader" data-test-id="routeHeader"
color={"text"} color={"text"}
title={title} title={title}
@@ -188,7 +181,7 @@ function RouteTitle({ title, isEditable, onChange }) {
m: 0, m: 0,
fontWeight: "bold", fontWeight: "bold",
fontFamily: "heading", fontFamily: "heading",
fontSize: "heading", fontSize: subtitle ? "subheading" : "heading",
border: "none", border: "none",
bg: isEditing ? "bgSecondary" : "transparent", bg: isEditing ? "bgSecondary" : "transparent",
@@ -213,5 +206,6 @@ function RouteTitle({ title, isEditable, onChange }) {
}} }}
readOnly={!isEditing} readOnly={!isEditing}
/> />
</Flex>
); );
} }

View File

@@ -44,12 +44,6 @@ const routes = {
return { return {
key: "topics", key: "topics",
type: "topics", type: "topics",
title: notebook.title,
isEditable: true,
onChange: (title) => {
db.notebooks.add({ id: notebookId, title });
showToast("success", "Notebook title updated!");
},
component: <Topics />, component: <Topics />,
buttons: { buttons: {
back: { back: {

View File

@@ -1,8 +1,14 @@
import React from "react"; import React, { useEffect, useState } from "react";
import ListContainer from "../components/list-container"; import ListContainer from "../components/list-container";
import { useStore as useNbStore } from "../stores/notebook-store"; import { useStore as useNbStore } from "../stores/notebook-store";
import { useStore as useAppStore } from "../stores/app-store";
import { hashNavigate } from "../navigation"; import { hashNavigate } from "../navigation";
import TopicsPlaceholder from "../components/placeholders/topics-placeholder"; import TopicsPlaceholder from "../components/placeholders/topics-placeholder";
import { Button, Flex, Text } from "rebass";
import { Edit, RemoveShortcutLink, ShortcutLink } from "../components/icons";
import { getTotalNotes } from "../common";
import { formatDate } from "notes-core/utils/date";
import { db } from "../common/db";
function Topics() { function Topics() {
const selectedNotebookTopics = useNbStore( const selectedNotebookTopics = useNbStore(
@@ -20,6 +26,11 @@ function Topics() {
items={selectedNotebookTopics} items={selectedNotebookTopics}
context={{ notebookId: selectedNotebookId }} context={{ notebookId: selectedNotebookId }}
placeholder={TopicsPlaceholder} placeholder={TopicsPlaceholder}
header={
<NotebookHeader
notebook={db.notebooks.notebook(selectedNotebookId).data}
/>
}
button={{ button={{
content: "Add a new topic", content: "Add a new topic",
onClick: () => hashNavigate(`/topics/create`), onClick: () => hashNavigate(`/topics/create`),
@@ -29,3 +40,60 @@ function Topics() {
); );
} }
export default Topics; export default Topics;
function NotebookHeader({ notebook }) {
const { title, description, topics, dateEdited } = notebook;
const [isShortcut, setIsShortcut] = useState(false);
const menuPins = useAppStore((store) => store.menuPins);
const pinItemToMenu = useAppStore((store) => store.pinItemToMenu);
useEffect(() => {
setIsShortcut(menuPins.findIndex((p) => p.id === notebook.id) > -1);
}, [menuPins, notebook]);
return (
<Flex flexDirection="column" mx={2} my={2}>
<Text variant="subBody">{formatDate(dateEdited)}</Text>
<Flex justifyContent="space-between" alignItems="center">
<Text variant="heading">{title}</Text>
<Flex>
<Button
variant="tool"
sx={{ borderRadius: 100 }}
mr={1}
p={0}
width={30}
height={30}
title={isShortcut ? "Remove shortcut" : "Create shortcut"}
onClick={() => pinItemToMenu(notebook)}
>
{isShortcut ? (
<RemoveShortcutLink size={16} />
) : (
<ShortcutLink size={16} />
)}
</Button>
<Button
variant="tool"
sx={{ borderRadius: 100 }}
p={0}
width={30}
height={30}
title="Edit notebook"
onClick={() => hashNavigate(`/notebooks/${notebook.id}/edit`)}
>
<Edit size={16} />
</Button>
</Flex>
</Flex>
{description && (
<Text variant="body" fontSize="subtitle">
{description}
</Text>
)}
<Text as="em" variant="subBody" mt={2}>
{topics.length} topic, {getTotalNotes(notebook)} notes
</Text>
</Flex>
);
}