mirror of
https://github.com/usememos/memos.git
synced 2025-02-12 09:20:42 +01:00
chore: tweak responsible styles
This commit is contained in:
parent
fe4ec0b156
commit
a3a1bbe8de
@ -20,8 +20,7 @@ VALUES
|
||||
'#TODO
|
||||
- [x] Take more photos about **🌄 sunset**;
|
||||
- [x] Clean the room;
|
||||
- [ ] Read *📖 The Little Prince*;
|
||||
(👆 click to toggle status)',
|
||||
- [ ] Read *📖 The Little Prince*;',
|
||||
101,
|
||||
'PROTECTED'
|
||||
);
|
||||
|
@ -72,7 +72,6 @@ const MemoEditor = (props: Props) => {
|
||||
|
||||
useEffect(() => {
|
||||
editorRef.current?.setContent(contentCache || "");
|
||||
handleEditorFocus();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,4 +1,6 @@
|
||||
import classNames from "classnames";
|
||||
import { useState } from "react";
|
||||
import { useWindowScroll } from "react-use";
|
||||
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
|
||||
import NavigationDrawer from "./NavigationDrawer";
|
||||
|
||||
@ -10,9 +12,15 @@ const MobileHeader = (props: Props) => {
|
||||
const { children } = props;
|
||||
const { sm } = useResponsiveWidth();
|
||||
const [titleText] = useState("MEMOS");
|
||||
const { y: offsetTop } = useWindowScroll();
|
||||
|
||||
return (
|
||||
<div className="sticky top-0 pt-4 sm:pt-1 pb-1 mb-1 backdrop-blur flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-2">
|
||||
<div
|
||||
className={classNames(
|
||||
"sticky top-0 pt-4 sm:pt-1 px-4 pb-1 mb-1 backdrop-blur flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-2",
|
||||
offsetTop > 0 && "shadow-md"
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row justify-start items-center mr-2 shrink-0 overflow-hidden">
|
||||
{!sm && <NavigationDrawer />}
|
||||
<span
|
||||
|
@ -1,5 +1,5 @@
|
||||
body {
|
||||
@apply text-base w-full min-h-full p-0 m-0 bg-zinc-100 dark:bg-zinc-800;
|
||||
@apply text-base w-full min-h-[100svh] p-0 m-0 bg-zinc-100 dark:bg-zinc-800;
|
||||
}
|
||||
|
||||
#root {
|
||||
|
@ -13,7 +13,7 @@ function Root() {
|
||||
<Navigation />
|
||||
</div>
|
||||
)}
|
||||
<main className="w-full sm:px-4 h-auto flex-grow shrink flex flex-col justify-start items-center">
|
||||
<main className="w-full h-auto flex-grow shrink flex flex-col justify-start items-center">
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
|
@ -30,24 +30,26 @@ const Archived = () => {
|
||||
}, [memos]);
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-start px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-start sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
{loadingState.isLoading ? (
|
||||
<div className="w-full h-32 flex flex-col justify-center items-center">
|
||||
<p className="opacity-70">{t("memo.fetching-data")}</p>
|
||||
</div>
|
||||
) : archivedMemos.length === 0 ? (
|
||||
<div className="w-full mt-16 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full flex flex-col justify-start items-start">
|
||||
{archivedMemos.map((memo) => (
|
||||
<ArchivedMemo key={`${memo.id}-${memo.updatedTs}`} memo={memo} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full px-4">
|
||||
{loadingState.isLoading ? (
|
||||
<div className="w-full h-32 flex flex-col justify-center items-center">
|
||||
<p className="opacity-70">{t("memo.fetching-data")}</p>
|
||||
</div>
|
||||
) : archivedMemos.length === 0 ? (
|
||||
<div className="w-full mt-16 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full flex flex-col justify-start items-start">
|
||||
{archivedMemos.map((memo) => (
|
||||
<ArchivedMemo key={`${memo.id}-${memo.updatedTs}`} memo={memo} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
@ -54,9 +54,9 @@ const Explore = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-center sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="relative w-full h-auto flex flex-col justify-start items-start">
|
||||
<div className="relative w-full h-auto flex flex-col justify-start items-start px-4">
|
||||
<MemoFilter />
|
||||
{sortedMemos.map((memo) => (
|
||||
<Memo key={memo.id} memo={memo} lazyRendering showCreator showParent />
|
||||
|
@ -9,14 +9,16 @@ const Home = () => {
|
||||
const { md } = useResponsiveWidth();
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-row justify-center items-start">
|
||||
<div className="w-full px-4 max-w-3xl sm:px-2 sm:pt-4">
|
||||
<div className="w-full max-w-4xl flex flex-row justify-center items-start">
|
||||
<div className="w-full sm:pt-4">
|
||||
<MobileHeader>{!md && <HomeSidebarDrawer />}</MobileHeader>
|
||||
<MemoEditor className="mb-2" cacheKey="home-memo-editor" />
|
||||
<MemoList />
|
||||
<div className="w-full px-4 md:pr-2">
|
||||
<MemoEditor className="mb-2" cacheKey="home-memo-editor" />
|
||||
<MemoList />
|
||||
</div>
|
||||
</div>
|
||||
{md && (
|
||||
<div className="hidden md:block sticky top-0 left-0 w-56">
|
||||
<div className="hidden md:block sticky top-0 left-0 shrink-0 w-56">
|
||||
<HomeSidebar />
|
||||
</div>
|
||||
)}
|
||||
|
@ -20,30 +20,32 @@ const Inboxes = () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-center sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-between items-center">
|
||||
<p className="px-2 py-1 flex flex-row justify-start items-center select-none opacity-80">
|
||||
<Icon.Bell className="w-5 h-auto mr-1" /> {t("common.inbox")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full h-auto flex flex-col justify-start items-start px-2 pb-4 bg-white dark:bg-zinc-700">
|
||||
{inboxes.length === 0 && (
|
||||
<div className="w-full mt-4 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
<div className="w-full px-4">
|
||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-between items-center">
|
||||
<p className="px-2 py-1 flex flex-row justify-start items-center select-none opacity-80">
|
||||
<Icon.Bell className="w-5 h-auto mr-1" /> {t("common.inbox")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full h-auto flex flex-col justify-start items-start px-2 pb-4 bg-white dark:bg-zinc-700">
|
||||
{inboxes.length === 0 && (
|
||||
<div className="w-full mt-4 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-start items-start w-full mt-4 gap-4">
|
||||
{inboxes.map((inbox) => {
|
||||
if (inbox.type === Inbox_Type.TYPE_MEMO_COMMENT) {
|
||||
return <MemoCommentMessage key={`${inbox.name}-${inbox.status}`} inbox={inbox} />;
|
||||
} else if (inbox.type === Inbox_Type.TYPE_VERSION_UPDATE) {
|
||||
return <VersionUpdateMessage key={`${inbox.name}-${inbox.status}`} inbox={inbox} />;
|
||||
}
|
||||
return undefined;
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-start items-start w-full mt-4 gap-4">
|
||||
{inboxes.map((inbox) => {
|
||||
if (inbox.type === Inbox_Type.TYPE_MEMO_COMMENT) {
|
||||
return <MemoCommentMessage key={`${inbox.name}-${inbox.status}`} inbox={inbox} />;
|
||||
} else if (inbox.type === Inbox_Type.TYPE_VERSION_UPDATE) {
|
||||
return <VersionUpdateMessage key={`${inbox.name}-${inbox.status}`} inbox={inbox} />;
|
||||
}
|
||||
return undefined;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -110,114 +110,116 @@ const MemoDetail = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-center sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="relative flex-grow w-full min-h-full flex flex-col justify-start items-start border dark:border-zinc-700 bg-white dark:bg-zinc-700 shadow hover:shadow-xl transition-all p-4 pb-3 rounded-lg">
|
||||
{memo.parent && (
|
||||
<div className="w-auto mb-2">
|
||||
<Link
|
||||
className="px-3 py-1 border rounded-full max-w-xs w-auto text-sm flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-400 dark:border-gray-500 hover:shadow hover:opacity-80"
|
||||
to={`/m/${memo.parent.id}`}
|
||||
>
|
||||
<Icon.ArrowUpLeftFromCircle className="w-4 h-auto shrink-0 opacity-60" />
|
||||
<span className="mx-1 opacity-60">#{memo.parent.id}</span>
|
||||
<span className="truncate">{memo.parent.content}</span>
|
||||
</Link>
|
||||
<div className="w-full px-4">
|
||||
<div className="relative flex-grow w-full min-h-full flex flex-col justify-start items-start border dark:border-zinc-700 bg-white dark:bg-zinc-700 shadow hover:shadow-xl transition-all p-4 pb-3 rounded-lg">
|
||||
{memo.parent && (
|
||||
<div className="w-auto mb-2">
|
||||
<Link
|
||||
className="px-3 py-1 border rounded-full max-w-xs w-auto text-sm flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-400 dark:border-gray-500 hover:shadow hover:opacity-80"
|
||||
to={`/m/${memo.parent.id}`}
|
||||
>
|
||||
<Icon.ArrowUpLeftFromCircle className="w-4 h-auto shrink-0 opacity-60" />
|
||||
<span className="mx-1 opacity-60">#{memo.parent.id}</span>
|
||||
<span className="truncate">{memo.parent.content}</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full mb-2 flex flex-row justify-start items-center">
|
||||
<span className="text-gray-400 select-none">{getDateTimeString(memo.displayTs)}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full mb-2 flex flex-row justify-start items-center">
|
||||
<span className="text-gray-400 select-none">{getDateTimeString(memo.displayTs)}</span>
|
||||
</div>
|
||||
<MemoContentV1 content={memo.content} />
|
||||
<MemoResourceListView resourceList={memo.resourceList} />
|
||||
<MemoRelationListView memo={memo} relationList={referenceRelations} />
|
||||
<div className="w-full mt-4 flex flex-col sm:flex-row justify-start sm:justify-between sm:items-center gap-2">
|
||||
<div className="flex flex-row justify-start items-center">
|
||||
<Tooltip title={"Identifier"} placement="top">
|
||||
<span className="text-sm text-gray-500 dark:text-gray-400">#{memo.id}</span>
|
||||
</Tooltip>
|
||||
<Icon.Dot className="w-4 h-auto text-gray-400 dark:text-zinc-400" />
|
||||
<Link to={`/u/${encodeURIComponent(memo.creatorUsername)}`}>
|
||||
<Tooltip title={"Creator"} placement="top">
|
||||
<span className="flex flex-row justify-start items-center">
|
||||
<UserAvatar className="!w-5 !h-5 mr-1" avatarUrl={creator?.avatarUrl} />
|
||||
<span className="text-sm text-gray-600 max-w-[8em] truncate dark:text-gray-400">{creator?.nickname}</span>
|
||||
</span>
|
||||
<MemoContentV1 content={memo.content} />
|
||||
<MemoResourceListView resourceList={memo.resourceList} />
|
||||
<MemoRelationListView memo={memo} relationList={referenceRelations} />
|
||||
<div className="w-full mt-4 flex flex-col sm:flex-row justify-start sm:justify-between sm:items-center gap-2">
|
||||
<div className="flex flex-row justify-start items-center">
|
||||
<Tooltip title={"Identifier"} placement="top">
|
||||
<span className="text-sm text-gray-500 dark:text-gray-400">#{memo.id}</span>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
{allowEdit && (
|
||||
<>
|
||||
<Icon.Dot className="w-4 h-auto text-gray-400 dark:text-zinc-400" />
|
||||
<Select
|
||||
className="w-auto text-sm"
|
||||
variant="plain"
|
||||
value={memo.visibility}
|
||||
startDecorator={<VisibilityIcon visibility={memo.visibility} />}
|
||||
onChange={(_, visibility) => {
|
||||
if (visibility) {
|
||||
handleMemoVisibilityOptionChanged(visibility);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
||||
<Option key={item} value={item} className="whitespace-nowrap" disabled={disableOption(item)}>
|
||||
{t(`memo.visibility.${item.toLowerCase() as Lowercase<typeof item>}`)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row sm:justify-end items-center">
|
||||
{allowEdit && (
|
||||
<Tooltip title={"Edit"} placement="top">
|
||||
<IconButton size="sm" onClick={handleEditMemoClick}>
|
||||
<Icon.Edit3 className="w-4 h-auto text-gray-600 dark:text-gray-400" />
|
||||
<Icon.Dot className="w-4 h-auto text-gray-400 dark:text-zinc-400" />
|
||||
<Link to={`/u/${encodeURIComponent(memo.creatorUsername)}`}>
|
||||
<Tooltip title={"Creator"} placement="top">
|
||||
<span className="flex flex-row justify-start items-center">
|
||||
<UserAvatar className="!w-5 !h-5 mr-1" avatarUrl={creator?.avatarUrl} />
|
||||
<span className="text-sm text-gray-600 max-w-[8em] truncate dark:text-gray-400">{creator?.nickname}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
{allowEdit && (
|
||||
<>
|
||||
<Icon.Dot className="w-4 h-auto text-gray-400 dark:text-zinc-400" />
|
||||
<Select
|
||||
className="w-auto text-sm"
|
||||
variant="plain"
|
||||
value={memo.visibility}
|
||||
startDecorator={<VisibilityIcon visibility={memo.visibility} />}
|
||||
onChange={(_, visibility) => {
|
||||
if (visibility) {
|
||||
handleMemoVisibilityOptionChanged(visibility);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
||||
<Option key={item} value={item} className="whitespace-nowrap" disabled={disableOption(item)}>
|
||||
{t(`memo.visibility.${item.toLowerCase() as Lowercase<typeof item>}`)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row sm:justify-end items-center">
|
||||
{allowEdit && (
|
||||
<Tooltip title={"Edit"} placement="top">
|
||||
<IconButton size="sm" onClick={handleEditMemoClick}>
|
||||
<Icon.Edit3 className="w-4 h-auto text-gray-600 dark:text-gray-400" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={"Copy link"} placement="top">
|
||||
<IconButton size="sm" onClick={handleCopyLinkBtnClick}>
|
||||
<Icon.Link className="w-4 h-auto text-gray-600 dark:text-gray-400" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={"Copy link"} placement="top">
|
||||
<IconButton size="sm" onClick={handleCopyLinkBtnClick}>
|
||||
<Icon.Link className="w-4 h-auto text-gray-600 dark:text-gray-400" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={"Share"} placement="top">
|
||||
<IconButton size="sm" onClick={() => showShareMemoDialog(memo)}>
|
||||
<Icon.Share className="w-4 h-auto text-gray-600 dark:text-gray-400" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={"Share"} placement="top">
|
||||
<IconButton size="sm" onClick={() => showShareMemoDialog(memo)}>
|
||||
<Icon.Share className="w-4 h-auto text-gray-600 dark:text-gray-400" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-8 pb-16 w-full">
|
||||
<div className="relative mx-auto flex-grow w-full min-h-full flex flex-col justify-start items-start gap-y-1">
|
||||
{comments.length === 0 ? (
|
||||
<div className="w-full flex flex-col justify-center items-center py-6 mb-2">
|
||||
<Icon.MessageCircle strokeWidth={1} className="w-8 h-auto text-gray-400" />
|
||||
<p className="text-gray-400 italic text-sm">{t("memo.comment.no-comment")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="w-full flex flex-row justify-start items-center pl-3 mb-3">
|
||||
<Icon.MessageCircle className="w-5 h-auto text-gray-400 mr-1" />
|
||||
<span className="text-gray-400 text-sm">{t("memo.comment.self")}</span>
|
||||
<span className="text-gray-400 text-sm ml-0.5">({comments.length})</span>
|
||||
<div className="pt-8 pb-16 w-full">
|
||||
<div className="relative mx-auto flex-grow w-full min-h-full flex flex-col justify-start items-start gap-y-1">
|
||||
{comments.length === 0 ? (
|
||||
<div className="w-full flex flex-col justify-center items-center py-6 mb-2">
|
||||
<Icon.MessageCircle strokeWidth={1} className="w-8 h-auto text-gray-400" />
|
||||
<p className="text-gray-400 italic text-sm">{t("memo.comment.no-comment")}</p>
|
||||
</div>
|
||||
{comments.map((comment) => (
|
||||
<Memo key={comment.id} memo={comment} showCreator />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
) : (
|
||||
<>
|
||||
<div className="w-full flex flex-row justify-start items-center pl-3 mb-3">
|
||||
<Icon.MessageCircle className="w-5 h-auto text-gray-400 mr-1" />
|
||||
<span className="text-gray-400 text-sm">{t("memo.comment.self")}</span>
|
||||
<span className="text-gray-400 text-sm ml-0.5">({comments.length})</span>
|
||||
</div>
|
||||
{comments.map((comment) => (
|
||||
<Memo key={comment.id} memo={comment} showCreator />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Only show comment editor when user login */}
|
||||
{currentUser && (
|
||||
<MemoEditor
|
||||
key={memo.id}
|
||||
cacheKey={`comment-editor-${memo.id}`}
|
||||
relationList={[{ memoId: UNKNOWN_ID, relatedMemoId: memo.id, type: "COMMENT" }]}
|
||||
onConfirm={handleCommentCreated}
|
||||
/>
|
||||
)}
|
||||
{/* Only show comment editor when user login */}
|
||||
{currentUser && (
|
||||
<MemoEditor
|
||||
key={memo.id}
|
||||
cacheKey={`comment-editor-${memo.id}`}
|
||||
relationList={[{ memoId: UNKNOWN_ID, relatedMemoId: memo.id, type: "COMMENT" }]}
|
||||
onConfirm={handleCommentCreated}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -66,106 +66,108 @@ const Resources = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-center sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-between items-center">
|
||||
<p className="px-2 py-1 flex flex-row justify-start items-center select-none opacity-80">
|
||||
<Icon.Paperclip className="w-5 h-auto mr-1" /> {t("common.resources")}
|
||||
</p>
|
||||
<div>
|
||||
<Input
|
||||
className="max-w-[8rem]"
|
||||
variant="plain"
|
||||
placeholder={t("common.search")}
|
||||
startDecorator={<Icon.Search className="w-4 h-auto" />}
|
||||
value={state.searchQuery}
|
||||
onChange={(e) => setState({ ...state, searchQuery: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full flex flex-col justify-start items-start mt-4 mb-6">
|
||||
{loadingState.isLoading ? (
|
||||
<div className="w-full h-32 flex flex-col justify-center items-center">
|
||||
<p className="w-full text-center text-base my-6 mt-8">{t("resource.fetching-data")}</p>
|
||||
<div className="w-full px-4">
|
||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-between items-center">
|
||||
<p className="px-2 py-1 flex flex-row justify-start items-center select-none opacity-80">
|
||||
<Icon.Paperclip className="w-5 h-auto mr-1" /> {t("common.resources")}
|
||||
</p>
|
||||
<div>
|
||||
<Input
|
||||
className="max-w-[8rem]"
|
||||
variant="plain"
|
||||
placeholder={t("common.search")}
|
||||
startDecorator={<Icon.Search className="w-4 h-auto" />}
|
||||
value={state.searchQuery}
|
||||
onChange={(e) => setState({ ...state, searchQuery: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{filteredResources.length === 0 ? (
|
||||
<div className="w-full mt-8 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className={"w-full h-auto px-2 flex flex-col justify-start items-start gap-y-8"}>
|
||||
{Array.from(groupedResources.entries()).map(([timestamp, resources]) => {
|
||||
const date = new Date(timestamp);
|
||||
return (
|
||||
<div key={timestamp} className="w-full flex flex-row justify-start items-start">
|
||||
<div className="w-16 sm:w-24 pt-4 sm:pl-4 flex flex-col justify-start items-start">
|
||||
<span className="text-sm opacity-60">{date.getFullYear()}</span>
|
||||
<span className="font-medium text-xl">{date.toLocaleString(i18n.language, { month: "short" })}</span>
|
||||
</div>
|
||||
<div className="w-full max-w-[calc(100%-4rem)] sm:max-w-[calc(100%-6rem)] flex flex-row justify-start items-start gap-4 flex-wrap">
|
||||
{resources.map((resource) => {
|
||||
return (
|
||||
<div key={resource.id} className="w-24 sm:w-32 h-auto flex flex-col justify-start items-start">
|
||||
<div className="w-24 h-24 flex justify-center items-center sm:w-32 sm:h-32 border dark:border-zinc-900 overflow-clip rounded-xl cursor-pointer hover:shadow hover:opacity-80">
|
||||
<ResourceIcon resource={resource} strokeWidth={0.5} />
|
||||
</div>
|
||||
<div className="w-full max-w-full flex flex-row justify-between items-center mt-1 px-1">
|
||||
<p className="text-xs shrink text-gray-400 truncate">{resource.filename}</p>
|
||||
<Link
|
||||
className="shrink-0 text-xs ml-1 text-gray-400 hover:underline hover:text-blue-600"
|
||||
to={`/m/${resource.memoId}`}
|
||||
target="_blank"
|
||||
>
|
||||
#{resource.memoId}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{unusedResources.length > 0 && (
|
||||
<>
|
||||
<Divider />
|
||||
<div className="w-full flex flex-row justify-start items-start">
|
||||
<div className="w-16 sm:w-24 sm:pl-4 flex flex-col justify-start items-start"></div>
|
||||
<div className="w-full max-w-[calc(100%-4rem)] sm:max-w-[calc(100%-6rem)] flex flex-row justify-start items-start gap-4 flex-wrap">
|
||||
<div className="w-full flex flex-row justify-start items-center gap-2">
|
||||
<span className="text-gray-600 dark:text-gray-400">Unused resources</span>
|
||||
<span className="text-gray-500 dark:text-gray-500 opacity-80">({unusedResources.length})</span>
|
||||
<Tooltip title="Delete all" placement="top">
|
||||
<IconButton size="sm" onClick={handleDeleteUnusedResources}>
|
||||
<Icon.Trash className="w-4 h-auto opacity-60" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="w-full flex flex-col justify-start items-start mt-4 mb-6">
|
||||
{loadingState.isLoading ? (
|
||||
<div className="w-full h-32 flex flex-col justify-center items-center">
|
||||
<p className="w-full text-center text-base my-6 mt-8">{t("resource.fetching-data")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{filteredResources.length === 0 ? (
|
||||
<div className="w-full mt-8 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className={"w-full h-auto px-2 flex flex-col justify-start items-start gap-y-8"}>
|
||||
{Array.from(groupedResources.entries()).map(([timestamp, resources]) => {
|
||||
const date = new Date(timestamp);
|
||||
return (
|
||||
<div key={timestamp} className="w-full flex flex-row justify-start items-start">
|
||||
<div className="w-16 sm:w-24 pt-4 sm:pl-4 flex flex-col justify-start items-start">
|
||||
<span className="text-sm opacity-60">{date.getFullYear()}</span>
|
||||
<span className="font-medium text-xl">{date.toLocaleString(i18n.language, { month: "short" })}</span>
|
||||
</div>
|
||||
{unusedResources.map((resource) => {
|
||||
return (
|
||||
<div key={resource.id} className="w-24 sm:w-32 h-auto flex flex-col justify-start items-start">
|
||||
<div className="w-24 h-24 flex justify-center items-center sm:w-32 sm:h-32 border dark:border-zinc-900 overflow-clip rounded-xl cursor-pointer hover:shadow hover:opacity-80">
|
||||
<ResourceIcon resource={resource} strokeWidth={0.5} />
|
||||
<div className="w-full max-w-[calc(100%-4rem)] sm:max-w-[calc(100%-6rem)] flex flex-row justify-start items-start gap-4 flex-wrap">
|
||||
{resources.map((resource) => {
|
||||
return (
|
||||
<div key={resource.id} className="w-24 sm:w-32 h-auto flex flex-col justify-start items-start">
|
||||
<div className="w-24 h-24 flex justify-center items-center sm:w-32 sm:h-32 border dark:border-zinc-900 overflow-clip rounded-xl cursor-pointer hover:shadow hover:opacity-80">
|
||||
<ResourceIcon resource={resource} strokeWidth={0.5} />
|
||||
</div>
|
||||
<div className="w-full max-w-full flex flex-row justify-between items-center mt-1 px-1">
|
||||
<p className="text-xs shrink text-gray-400 truncate">{resource.filename}</p>
|
||||
<Link
|
||||
className="shrink-0 text-xs ml-1 text-gray-400 hover:underline hover:text-blue-600"
|
||||
to={`/m/${resource.memoId}`}
|
||||
target="_blank"
|
||||
>
|
||||
#{resource.memoId}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-full flex flex-row justify-between items-center mt-1 px-1">
|
||||
<p className="text-xs shrink text-gray-400 truncate">{resource.filename}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
);
|
||||
})}
|
||||
|
||||
{unusedResources.length > 0 && (
|
||||
<>
|
||||
<Divider />
|
||||
<div className="w-full flex flex-row justify-start items-start">
|
||||
<div className="w-16 sm:w-24 sm:pl-4 flex flex-col justify-start items-start"></div>
|
||||
<div className="w-full max-w-[calc(100%-4rem)] sm:max-w-[calc(100%-6rem)] flex flex-row justify-start items-start gap-4 flex-wrap">
|
||||
<div className="w-full flex flex-row justify-start items-center gap-2">
|
||||
<span className="text-gray-600 dark:text-gray-400">Unused resources</span>
|
||||
<span className="text-gray-500 dark:text-gray-500 opacity-80">({unusedResources.length})</span>
|
||||
<Tooltip title="Delete all" placement="top">
|
||||
<IconButton size="sm" onClick={handleDeleteUnusedResources}>
|
||||
<Icon.Trash className="w-4 h-auto opacity-60" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{unusedResources.map((resource) => {
|
||||
return (
|
||||
<div key={resource.id} className="w-24 sm:w-32 h-auto flex flex-col justify-start items-start">
|
||||
<div className="w-24 h-24 flex justify-center items-center sm:w-32 sm:h-32 border dark:border-zinc-900 overflow-clip rounded-xl cursor-pointer hover:shadow hover:opacity-80">
|
||||
<ResourceIcon resource={resource} strokeWidth={0.5} />
|
||||
</div>
|
||||
<div className="w-full max-w-full flex flex-row justify-between items-center mt-1 px-1">
|
||||
<p className="text-xs shrink text-gray-400 truncate">{resource.filename}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -42,82 +42,84 @@ const Setting = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-start px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-start sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="setting-page-wrapper">
|
||||
<div className="section-selector-container">
|
||||
<span className="section-title">{t("common.basic")}</span>
|
||||
<div className="section-items-container">
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("my-account")}
|
||||
className={`section-item ${state.selectedSection === "my-account" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.User className="w-4 h-auto mr-2 opacity-80" /> {t("setting.my-account")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("preference")}
|
||||
className={`section-item ${state.selectedSection === "preference" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Cog className="w-4 h-auto mr-2 opacity-80" /> {t("setting.preference")}
|
||||
</span>
|
||||
<div className="w-full px-4">
|
||||
<div className="setting-page-wrapper">
|
||||
<div className="section-selector-container">
|
||||
<span className="section-title">{t("common.basic")}</span>
|
||||
<div className="section-items-container">
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("my-account")}
|
||||
className={`section-item ${state.selectedSection === "my-account" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.User className="w-4 h-auto mr-2 opacity-80" /> {t("setting.my-account")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("preference")}
|
||||
className={`section-item ${state.selectedSection === "preference" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Cog className="w-4 h-auto mr-2 opacity-80" /> {t("setting.preference")}
|
||||
</span>
|
||||
</div>
|
||||
{isHost ? (
|
||||
<>
|
||||
<span className="section-title">{t("common.admin")}</span>
|
||||
<div className="section-items-container">
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("member")}
|
||||
className={`section-item ${state.selectedSection === "member" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Users className="w-4 h-auto mr-2 opacity-80" /> {t("setting.member")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("system")}
|
||||
className={`section-item ${state.selectedSection === "system" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Settings2 className="w-4 h-auto mr-2 opacity-80" /> {t("setting.system")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("storage")}
|
||||
className={`section-item ${state.selectedSection === "storage" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Database className="w-4 h-auto mr-2 opacity-80" /> {t("setting.storage")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("sso")}
|
||||
className={`section-item ${state.selectedSection === "sso" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Key className="w-4 h-auto mr-2 opacity-80" /> {t("setting.sso")}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="section-content-container sm:max-w-[calc(100%-12rem)]">
|
||||
<Select
|
||||
className="block mb-2 sm:!hidden"
|
||||
value={state.selectedSection}
|
||||
onChange={(_, value) => handleSectionSelectorItemClick(value as SettingSection)}
|
||||
>
|
||||
{getSettingSectionList().map((settingSection) => (
|
||||
<Option key={settingSection} value={settingSection}>
|
||||
{t(`setting.${settingSection}`)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
{state.selectedSection === "my-account" ? (
|
||||
<MyAccountSection />
|
||||
) : state.selectedSection === "preference" ? (
|
||||
<PreferencesSection />
|
||||
) : state.selectedSection === "member" ? (
|
||||
<MemberSection />
|
||||
) : state.selectedSection === "system" ? (
|
||||
<SystemSection />
|
||||
) : state.selectedSection === "storage" ? (
|
||||
<StorageSection />
|
||||
) : state.selectedSection === "sso" ? (
|
||||
<SSOSection />
|
||||
) : null}
|
||||
</div>
|
||||
{isHost ? (
|
||||
<>
|
||||
<span className="section-title">{t("common.admin")}</span>
|
||||
<div className="section-items-container">
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("member")}
|
||||
className={`section-item ${state.selectedSection === "member" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Users className="w-4 h-auto mr-2 opacity-80" /> {t("setting.member")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("system")}
|
||||
className={`section-item ${state.selectedSection === "system" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Settings2 className="w-4 h-auto mr-2 opacity-80" /> {t("setting.system")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("storage")}
|
||||
className={`section-item ${state.selectedSection === "storage" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Database className="w-4 h-auto mr-2 opacity-80" /> {t("setting.storage")}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => handleSectionSelectorItemClick("sso")}
|
||||
className={`section-item ${state.selectedSection === "sso" ? "selected" : ""}`}
|
||||
>
|
||||
<Icon.Key className="w-4 h-auto mr-2 opacity-80" /> {t("setting.sso")}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="section-content-container sm:max-w-[calc(100%-12rem)]">
|
||||
<Select
|
||||
className="block mb-2 sm:!hidden"
|
||||
value={state.selectedSection}
|
||||
onChange={(_, value) => handleSectionSelectorItemClick(value as SettingSection)}
|
||||
>
|
||||
{getSettingSectionList().map((settingSection) => (
|
||||
<Option key={settingSection} value={settingSection}>
|
||||
{t(`setting.${settingSection}`)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
{state.selectedSection === "my-account" ? (
|
||||
<MyAccountSection />
|
||||
) : state.selectedSection === "preference" ? (
|
||||
<PreferencesSection />
|
||||
) : state.selectedSection === "member" ? (
|
||||
<MemberSection />
|
||||
) : state.selectedSection === "system" ? (
|
||||
<SystemSection />
|
||||
) : state.selectedSection === "storage" ? (
|
||||
<StorageSection />
|
||||
) : state.selectedSection === "sso" ? (
|
||||
<SSOSection />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -104,7 +104,7 @@ const SignIn = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="pt-12 pb-8 w-80 max-w-full h-auto mx-auto flex flex-col justify-start items-center">
|
||||
<div className="py-8 w-80 max-w-full min-h-[100svh] mx-auto flex flex-col justify-start items-center">
|
||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||
<div className="w-full flex flex-row justify-center items-center mb-6">
|
||||
<img className="h-14 w-auto rounded-full shadow" src={systemStatus.customizedProfile.logoUrl} alt="" />
|
||||
|
@ -70,7 +70,7 @@ const SignUp = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="pt-12 pb-8 w-80 max-w-full h-auto mx-auto flex flex-col justify-start items-center">
|
||||
<div className="py-8 w-80 max-w-full min-h-[100svh] mx-auto flex flex-col justify-start items-center">
|
||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||
<div className="w-full flex flex-row justify-center items-center mb-6">
|
||||
<img className="h-14 w-auto rounded-full shadow" src={systemStatus.customizedProfile.logoUrl} alt="" />
|
||||
|
@ -64,73 +64,75 @@ const Timeline = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8">
|
||||
<section className="@container w-full max-w-4xl min-h-full flex flex-col justify-start items-center sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-start items-center">
|
||||
<p
|
||||
className="px-2 py-1 mr-2 flex flex-row justify-start items-center cursor-pointer select-none rounded opacity-80 hover:bg-gray-100 dark:hover:bg-zinc-700"
|
||||
onClick={() => toggleShowDatePicker()}
|
||||
>
|
||||
<Icon.Calendar className="w-5 h-auto mr-2" />
|
||||
<span className="font-mono mt-0.5">{new Date(selectedDateStamp).toLocaleDateString()}</span>
|
||||
</p>
|
||||
{selectedDateStamp !== currentDateStamp && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
startDecorator={<Icon.Undo2 className="w-5 h-auto" />}
|
||||
onClick={() => setSelectedDateStamp(currentDateStamp)}
|
||||
<div className="w-full px-4">
|
||||
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-start items-center">
|
||||
<p
|
||||
className="px-2 py-1 mr-2 flex flex-row justify-start items-center cursor-pointer select-none rounded opacity-80 hover:bg-gray-100 dark:hover:bg-zinc-700"
|
||||
onClick={() => toggleShowDatePicker()}
|
||||
>
|
||||
{"Back to today"}
|
||||
</Button>
|
||||
)}
|
||||
<DatePicker
|
||||
className={`absolute top-8 mt-2 z-20 mx-auto border bg-white shadow dark:bg-zinc-800 dark:border-zinc-800 rounded-lg mb-6 ${
|
||||
showDatePicker ? "" : "!hidden"
|
||||
}`}
|
||||
datestamp={selectedDateStamp}
|
||||
isFutureDateDisabled
|
||||
handleDateStampChange={handleDataPickerChange}
|
||||
handleClickAway={() => toggleShowDatePicker(false)}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full h-auto flex flex-col justify-start items-start px-2 pb-4 bg-white dark:bg-zinc-700">
|
||||
{dailyMemos.length === 0 && (
|
||||
<div className="w-full mt-4 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-start items-start w-full mt-2">
|
||||
{dailyMemos.map((memo, index) => (
|
||||
<div
|
||||
key={`${memo.id}-${memo.displayTs}`}
|
||||
className="relative w-full flex flex-col justify-start items-start pl-8 sm:pl-12 pt-2 pb-4"
|
||||
<Icon.Calendar className="w-5 h-auto mr-2" />
|
||||
<span className="font-mono mt-0.5">{new Date(selectedDateStamp).toLocaleDateString()}</span>
|
||||
</p>
|
||||
{selectedDateStamp !== currentDateStamp && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
startDecorator={<Icon.Undo2 className="w-5 h-auto" />}
|
||||
onClick={() => setSelectedDateStamp(currentDateStamp)}
|
||||
>
|
||||
<div className="w-full flex flex-row justify-start items-center mt-0.5 mb-1 text-sm font-mono text-gray-500 dark:text-gray-400">
|
||||
<span className="opacity-80">{getTimeString(memo.displayTs)}</span>
|
||||
<Icon.Dot className="w-5 h-auto opacity-60" />
|
||||
<span className="opacity-60">#{memo.id}</span>
|
||||
</div>
|
||||
<MemoContentV1 content={memo.content} />
|
||||
<MemoResourceListView resourceList={memo.resourceList} />
|
||||
<MemoRelationListView memo={memo} relationList={memo.relationList.filter((relation) => relation.type === "REFERENCE")} />
|
||||
<div className="absolute left-1 sm:left-2 top-3 h-full">
|
||||
{index !== dailyMemos.length - 1 && (
|
||||
<div className="absolute top-2 left-[7px] h-full w-0.5 bg-gray-400 dark:bg-gray-500 block"></div>
|
||||
)}
|
||||
<div className="border-4 rounded-full border-white relative dark:border-zinc-700">
|
||||
<Icon.Circle className="w-2 h-auto bg-gray-400 text-gray-400 dark:bg-gray-500 dark:text-gray-500 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{selectedDateStamp === currentDateStamp && (
|
||||
<div className="w-full pl-0 sm:pl-12 sm:mt-4">
|
||||
<MemoEditor cacheKey="timeline-editor" />
|
||||
{"Back to today"}
|
||||
</Button>
|
||||
)}
|
||||
<DatePicker
|
||||
className={`absolute top-8 mt-2 z-20 mx-auto border bg-white shadow dark:bg-zinc-800 dark:border-zinc-800 rounded-lg mb-6 ${
|
||||
showDatePicker ? "" : "!hidden"
|
||||
}`}
|
||||
datestamp={selectedDateStamp}
|
||||
isFutureDateDisabled
|
||||
handleDateStampChange={handleDataPickerChange}
|
||||
handleClickAway={() => toggleShowDatePicker(false)}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full h-auto flex flex-col justify-start items-start px-2 pb-4 bg-white dark:bg-zinc-700">
|
||||
{dailyMemos.length === 0 && (
|
||||
<div className="w-full mt-4 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-start items-start w-full mt-2">
|
||||
{dailyMemos.map((memo, index) => (
|
||||
<div
|
||||
key={`${memo.id}-${memo.displayTs}`}
|
||||
className="relative w-full flex flex-col justify-start items-start pl-8 sm:pl-12 pt-2 pb-4"
|
||||
>
|
||||
<div className="w-full flex flex-row justify-start items-center mt-0.5 mb-1 text-sm font-mono text-gray-500 dark:text-gray-400">
|
||||
<span className="opacity-80">{getTimeString(memo.displayTs)}</span>
|
||||
<Icon.Dot className="w-5 h-auto opacity-60" />
|
||||
<span className="opacity-60">#{memo.id}</span>
|
||||
</div>
|
||||
<MemoContentV1 content={memo.content} />
|
||||
<MemoResourceListView resourceList={memo.resourceList} />
|
||||
<MemoRelationListView memo={memo} relationList={memo.relationList.filter((relation) => relation.type === "REFERENCE")} />
|
||||
<div className="absolute left-1 sm:left-2 top-3 h-full">
|
||||
{index !== dailyMemos.length - 1 && (
|
||||
<div className="absolute top-2 left-[7px] h-full w-0.5 bg-gray-400 dark:bg-gray-500 block"></div>
|
||||
)}
|
||||
<div className="border-4 rounded-full border-white relative dark:border-zinc-700">
|
||||
<Icon.Circle className="w-2 h-auto bg-gray-400 text-gray-400 dark:bg-gray-500 dark:text-gray-500 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{selectedDateStamp === currentDateStamp && (
|
||||
<div className="w-full pl-0 sm:pl-12 sm:mt-4">
|
||||
<MemoEditor cacheKey="timeline-editor" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -35,28 +35,20 @@ const UserProfile = () => {
|
||||
}, [params.username]);
|
||||
|
||||
return (
|
||||
<section className="relative top-0 w-full min-h-full overflow-x-hidden">
|
||||
<section className="w-full max-w-4xl min-h-full flex flex-col justify-start items-center sm:pt-4 pb-8">
|
||||
<MobileHeader />
|
||||
<div className="relative w-full min-h-full mx-auto flex flex-col justify-start items-center">
|
||||
<div className="w-full px-4 flex flex-col justify-start items-center">
|
||||
{!loadingState.isLoading &&
|
||||
(user ? (
|
||||
<>
|
||||
<div className="relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4">
|
||||
<div className="w-full flex flex-row justify-start items-start">
|
||||
<div className="flex-grow shrink w-full">
|
||||
<div className="w-full flex flex-col justify-start items-center py-8">
|
||||
<UserAvatar className="!w-20 !h-20 mb-2 drop-shadow" avatarUrl={user?.avatarUrl} />
|
||||
<p className="text-3xl text-black opacity-80 dark:text-gray-200">{user?.nickname}</p>
|
||||
</div>
|
||||
<MemoList />
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full flex flex-col justify-start items-center py-8">
|
||||
<UserAvatar className="!w-20 !h-20 mb-2 drop-shadow" avatarUrl={user?.avatarUrl} />
|
||||
<p className="text-3xl text-black opacity-80 dark:text-gray-200">{user?.nickname}</p>
|
||||
</div>
|
||||
<MemoList />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p>Not found</p>
|
||||
</>
|
||||
<p>Not found</p>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
Loading…
x
Reference in New Issue
Block a user