mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
chore: tweak timeline styles
This commit is contained in:
23
web/src/components/TimelineSidebar.tsx
Normal file
23
web/src/components/TimelineSidebar.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import SearchBar from "./SearchBar";
|
||||||
|
import TagList from "./TagList";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimelineSidebar = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<aside
|
||||||
|
className={classNames(
|
||||||
|
"relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start",
|
||||||
|
props.className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<SearchBar />
|
||||||
|
<TagList />
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TimelineSidebar;
|
37
web/src/components/TimelineSidebarDrawer.tsx
Normal file
37
web/src/components/TimelineSidebarDrawer.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { Drawer, IconButton } from "@mui/joy";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
import Icon from "./Icon";
|
||||||
|
import TimelineSidebar from "./TimelineSidebar";
|
||||||
|
|
||||||
|
const TimelineSidebarDrawer = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setOpen(false);
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
const toggleDrawer = (inOpen: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => {
|
||||||
|
if (event.type === "keydown" && ((event as React.KeyboardEvent).key === "Tab" || (event as React.KeyboardEvent).key === "Shift")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen(inOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IconButton onClick={toggleDrawer(true)}>
|
||||||
|
<Icon.Search className="w-5 h-auto dark:text-gray-400" />
|
||||||
|
</IconButton>
|
||||||
|
<Drawer anchor="right" size="sm" open={open} onClose={toggleDrawer(false)}>
|
||||||
|
<div className="w-full h-full px-5 bg-zinc-100 dark:bg-zinc-900">
|
||||||
|
<TimelineSidebar className="py-4" />
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TimelineSidebarDrawer;
|
@@ -1,6 +1,5 @@
|
|||||||
import { Button, Divider, IconButton } from "@mui/joy";
|
import { Button, Divider, IconButton } from "@mui/joy";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { sum } from "lodash-es";
|
|
||||||
import { Fragment, useEffect, useRef, useState } from "react";
|
import { Fragment, useEffect, useRef, useState } from "react";
|
||||||
import ActivityCalendar from "@/components/ActivityCalendar";
|
import ActivityCalendar from "@/components/ActivityCalendar";
|
||||||
import Empty from "@/components/Empty";
|
import Empty from "@/components/Empty";
|
||||||
@@ -9,6 +8,8 @@ import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog";
|
|||||||
import MemoFilter from "@/components/MemoFilter";
|
import MemoFilter from "@/components/MemoFilter";
|
||||||
import MemoView from "@/components/MemoView";
|
import MemoView from "@/components/MemoView";
|
||||||
import MobileHeader from "@/components/MobileHeader";
|
import MobileHeader from "@/components/MobileHeader";
|
||||||
|
import TimelineSidebar from "@/components/TimelineSidebar";
|
||||||
|
import TimelineSidebarDrawer from "@/components/TimelineSidebarDrawer";
|
||||||
import { memoServiceClient } from "@/grpcweb";
|
import { memoServiceClient } from "@/grpcweb";
|
||||||
import { DAILY_TIMESTAMP, DEFAULT_MEMO_LIMIT } from "@/helpers/consts";
|
import { DAILY_TIMESTAMP, DEFAULT_MEMO_LIMIT } from "@/helpers/consts";
|
||||||
import { getNormalizedTimeString, getTimeStampByDate } from "@/helpers/datetime";
|
import { getNormalizedTimeString, getTimeStampByDate } from "@/helpers/datetime";
|
||||||
@@ -120,8 +121,13 @@ const Timeline = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
|
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
|
||||||
<MobileHeader />
|
{!md && (
|
||||||
<div className="w-full px-4 sm:px-6">
|
<MobileHeader>
|
||||||
|
<TimelineSidebarDrawer />
|
||||||
|
</MobileHeader>
|
||||||
|
)}
|
||||||
|
<div className={classNames("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}>
|
||||||
|
<div className={classNames(md ? "w-[calc(100%-15rem)]" : "w-full")}>
|
||||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300">
|
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300">
|
||||||
<div className="relative w-full flex flex-row justify-between items-center">
|
<div className="relative w-full flex flex-row justify-between items-center">
|
||||||
<div>
|
<div>
|
||||||
@@ -144,26 +150,24 @@ const Timeline = () => {
|
|||||||
|
|
||||||
{groupedByMonth.map((group, index) => (
|
{groupedByMonth.map((group, index) => (
|
||||||
<Fragment key={group.month}>
|
<Fragment key={group.month}>
|
||||||
<div className={classNames("flex justify-start items-start w-full mt-2 last:mb-4", md ? "flex-row" : "flex-col")}>
|
<div className={classNames("flex flex-col justify-start items-start w-full mt-2 last:mb-4")}>
|
||||||
<div className={classNames("flex shrink-0", md ? "flex-col w-40 pr-4 pl-2 pb-8" : "flex-row w-full pl-1 mt-2 mb-2")}>
|
<div className={classNames("flex shrink-0 flex-row w-full pl-1 mt-2 mb-2")}>
|
||||||
<div className={classNames("w-full flex flex-col", md && "mt-4 mb-2")}>
|
<div className={classNames("w-full flex flex-col")}>
|
||||||
<span className="font-medium text-3xl leading-none mb-1">
|
<span className="font-medium text-3xl leading-none mb-1">
|
||||||
{new Date(group.month).toLocaleString(i18n.language, { month: "short", timeZone: "UTC" })}
|
{new Date(group.month).toLocaleString(i18n.language, { month: "short", timeZone: "UTC" })}
|
||||||
</span>
|
</span>
|
||||||
<span className="opacity-60">{new Date(group.month).getUTCFullYear()}</span>
|
<span className="opacity-60">{new Date(group.month).getUTCFullYear()}</span>
|
||||||
<span className="text-xs opacity-40">Total: {sum(Object.values(group.data))}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<ActivityCalendar month={group.month} data={group.data} onClick={(date) => setSelectedDay(date)} />
|
<ActivityCalendar month={group.month} data={group.data} onClick={(date) => setSelectedDay(date)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={classNames("flex flex-col justify-start items-start", md ? "w-[calc(100%-8rem)]" : "w-full")}>
|
<div className={classNames("w-full flex flex-col justify-start items-start")}>
|
||||||
{group.memos.map((memo, index) => (
|
{group.memos.map((memo, index) => (
|
||||||
<div
|
<div
|
||||||
key={`${memo.id}-${memo.displayTime}`}
|
key={`${memo.id}-${memo.displayTime}`}
|
||||||
className={classNames("relative w-full flex flex-col justify-start items-start pl-4 sm:pl-10 pt-0")}
|
className={classNames("relative w-full flex flex-col justify-start items-start pl-4 sm:pl-10 pt-0")}
|
||||||
>
|
>
|
||||||
<MemoView className="!border !border-gray-100 dark:!border-zinc-700" memo={memo} />
|
<MemoView className="!border max-w-full !border-gray-100 dark:!border-zinc-700" memo={memo} />
|
||||||
{group.memos.length > 1 && (
|
|
||||||
<div className="absolute -left-2 sm:left-2 top-4 h-full">
|
<div className="absolute -left-2 sm:left-2 top-4 h-full">
|
||||||
{index !== group.memos.length - 1 && (
|
{index !== group.memos.length - 1 && (
|
||||||
<div className="absolute top-2 left-[7px] h-full w-0.5 bg-gray-200 dark:bg-gray-700 block"></div>
|
<div className="absolute top-2 left-[7px] h-full w-0.5 bg-gray-200 dark:bg-gray-700 block"></div>
|
||||||
@@ -172,7 +176,6 @@ const Timeline = () => {
|
|||||||
<Icon.Circle className="w-2 h-auto bg-gray-200 text-gray-200 dark:bg-gray-700 dark:text-gray-700 rounded-full" />
|
<Icon.Circle className="w-2 h-auto bg-gray-200 text-gray-200 dark:bg-gray-700 dark:text-gray-700 rounded-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -202,6 +205,12 @@ const Timeline = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{md && (
|
||||||
|
<div className="sticky top-0 left-0 shrink-0 -mt-6 w-56 h-full">
|
||||||
|
<TimelineSidebar className="py-6" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -2,7 +2,7 @@ import react from "@vitejs/plugin-react";
|
|||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
let devProxyServer = "http://localhost:8081/";
|
let devProxyServer = "http://localhost:8081";
|
||||||
if (process.env.DEV_PROXY_SERVER && process.env.DEV_PROXY_SERVER.length > 0) {
|
if (process.env.DEV_PROXY_SERVER && process.env.DEV_PROXY_SERVER.length > 0) {
|
||||||
console.log("Use devProxyServer from environment: ", process.env.DEV_PROXY_SERVER);
|
console.log("Use devProxyServer from environment: ", process.env.DEV_PROXY_SERVER);
|
||||||
devProxyServer = process.env.DEV_PROXY_SERVER;
|
devProxyServer = process.env.DEV_PROXY_SERVER;
|
||||||
|
Reference in New Issue
Block a user