chore(frontend): fix clsx

pull/4339/head
johnnyjoy 3 months ago
parent 57014e392f
commit 0b85cb567e

@ -1,11 +1,10 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useWorkspaceSettingStore } from "@/store/v1"; import { useWorkspaceSettingStore } from "@/store/v1";
import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service"; import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { cn } from "@/utils/utils";
interface Props { interface Props {
month: string; // Format: 2021-1 month: string; // Format: 2021-1
@ -66,9 +65,9 @@ const ActivityCalendar = (props: Props) => {
} }
return ( return (
<div className={clsx("w-full h-auto shrink-0 grid grid-cols-7 grid-flow-row gap-1")}> <div className={cn("w-full h-auto shrink-0 grid grid-cols-7 grid-flow-row gap-1")}>
{weekDays.map((day, index) => ( {weekDays.map((day, index) => (
<div key={index} className={clsx("w-6 h-5 text-xs flex justify-center items-center cursor-default opacity-60")}> <div key={index} className={cn("w-6 h-5 text-xs flex justify-center items-center cursor-default opacity-60")}>
{day} {day}
</div> </div>
))} ))}

@ -1,5 +1,4 @@
import { CssVarsProvider } from "@mui/joy"; import { CssVarsProvider } from "@mui/joy";
import clsx from "clsx";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
@ -7,6 +6,7 @@ import CommonContextProvider from "@/layouts/CommonContextProvider";
import store from "@/store"; import store from "@/store";
import { useDialogStore } from "@/store/module"; import { useDialogStore } from "@/store/module";
import theme from "@/theme"; import theme from "@/theme";
import { cn } from "@/utils";
import "@/less/base-dialog.less"; import "@/less/base-dialog.less";
interface DialogConfig { interface DialogConfig {
@ -56,8 +56,8 @@ const BaseDialog: React.FC<Props> = (props: Props) => {
}; };
return ( return (
<div className={clsx("dialog-wrapper", className)} onMouseDown={handleSpaceClicked}> <div className={cn("dialog-wrapper", className)} onMouseDown={handleSpaceClicked}>
<div ref={dialogContainerRef} className={clsx("dialog-container")} onMouseDown={(e) => e.stopPropagation()}> <div ref={dialogContainerRef} className={cn("dialog-container")} onMouseDown={(e) => e.stopPropagation()}>
{children} {children}
</div> </div>
</div> </div>

@ -1,7 +1,7 @@
import clsx from "clsx";
import useDebounce from "react-use/lib/useDebounce"; import useDebounce from "react-use/lib/useDebounce";
import SearchBar from "@/components/SearchBar"; import SearchBar from "@/components/SearchBar";
import { useUserStatsStore } from "@/store/v1"; import { useUserStatsStore } from "@/store/v1";
import { cn } from "@/utils";
import TagsSection from "../HomeSidebar/TagsSection"; import TagsSection from "../HomeSidebar/TagsSection";
import StatisticsView from "../StatisticsView"; import StatisticsView from "../StatisticsView";
@ -22,7 +22,7 @@ const ExploreSidebar = (props: Props) => {
return ( return (
<aside <aside
className={clsx( className={cn(
"relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start", "relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start",
props.className, props.className,
)} )}

@ -1,9 +1,9 @@
import clsx from "clsx";
import useDebounce from "react-use/lib/useDebounce"; import useDebounce from "react-use/lib/useDebounce";
import SearchBar from "@/components/SearchBar"; import SearchBar from "@/components/SearchBar";
import StatisticsView from "@/components/StatisticsView"; import StatisticsView from "@/components/StatisticsView";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoList, useUserStatsStore } from "@/store/v1"; import { useMemoList, useUserStatsStore } from "@/store/v1";
import { cn } from "@/utils";
import TagsSection from "./TagsSection"; import TagsSection from "./TagsSection";
interface Props { interface Props {
@ -25,7 +25,7 @@ const HomeSidebar = (props: Props) => {
return ( return (
<aside <aside
className={clsx( className={cn(
"relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start", "relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start",
props.className, props.className,
)} )}

@ -1,10 +1,10 @@
import { Dropdown, Menu, MenuButton, MenuItem, Switch } from "@mui/joy"; import { Dropdown, Menu, MenuButton, MenuItem, Switch } from "@mui/joy";
import clsx from "clsx";
import { Edit3Icon, HashIcon, MoreVerticalIcon, TagsIcon, TrashIcon } from "lucide-react"; import { Edit3Icon, HashIcon, MoreVerticalIcon, TagsIcon, TrashIcon } from "lucide-react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import useLocalStorage from "react-use/lib/useLocalStorage"; import useLocalStorage from "react-use/lib/useLocalStorage";
import { memoServiceClient } from "@/grpcweb"; import { memoServiceClient } from "@/grpcweb";
import { useMemoFilterStore, useUserStatsStore, useUserStatsTags } from "@/store/v1"; import { useMemoFilterStore, useUserStatsStore, useUserStatsTags } from "@/store/v1";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import showRenameTagDialog from "../RenameTagDialog"; import showRenameTagDialog from "../RenameTagDialog";
import TagTree from "../TagTree"; import TagTree from "../TagTree";
@ -94,7 +94,7 @@ const TagsSection = (props: Props) => {
</Menu> </Menu>
</Dropdown> </Dropdown>
<div <div
className={clsx("inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]")} className={cn("inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]")}
onClick={() => handleTagClick(tag)} onClick={() => handleTagClick(tag)}
> >
<span className="truncate dark:opacity-80">{tag}</span> <span className="truncate dark:opacity-80">{tag}</span>

@ -1,5 +1,4 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { InboxIcon, LoaderIcon, MessageCircleIcon } from "lucide-react"; import { InboxIcon, LoaderIcon, MessageCircleIcon } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
@ -10,6 +9,7 @@ import { activityNamePrefix, useInboxStore, useMemoStore, useUserStore } from "@
import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service"; import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { User } from "@/types/proto/api/v1/user_service"; import { User } from "@/types/proto/api/v1/user_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { memoLink } from "@/utils/memo"; import { memoLink } from "@/utils/memo";
@ -74,7 +74,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
return ( return (
<div className="w-full flex flex-row justify-start items-start gap-3"> <div className="w-full flex flex-row justify-start items-start gap-3">
<div <div
className={clsx( className={cn(
"shrink-0 mt-2 p-2 rounded-full border", "shrink-0 mt-2 p-2 rounded-full border",
inbox.status === Inbox_Status.UNREAD inbox.status === Inbox_Status.UNREAD
? "border-blue-600 text-blue-600 bg-blue-50 dark:bg-zinc-800" ? "border-blue-600 text-blue-600 bg-blue-50 dark:bg-zinc-800"
@ -86,7 +86,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
</Tooltip> </Tooltip>
</div> </div>
<div <div
className={clsx( className={cn(
"border w-full p-2 px-3 rounded-lg flex flex-col justify-start items-start gap-1 dark:border-zinc-700 hover:bg-gray-100 dark:hover:bg-zinc-700", "border w-full p-2 px-3 rounded-lg flex flex-col justify-start items-start gap-1 dark:border-zinc-700 hover:bg-gray-100 dark:hover:bg-zinc-700",
inbox.status !== Inbox_Status.UNREAD && "opacity-60", inbox.status !== Inbox_Status.UNREAD && "opacity-60",
)} )}

@ -1,5 +1,4 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { ArrowUpIcon, InboxIcon } from "lucide-react"; import { ArrowUpIcon, InboxIcon } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
@ -7,6 +6,7 @@ import { activityServiceClient } from "@/grpcweb";
import { activityNamePrefix, useInboxStore } from "@/store/v1"; import { activityNamePrefix, useInboxStore } from "@/store/v1";
import { Activity } from "@/types/proto/api/v1/activity_service"; import { Activity } from "@/types/proto/api/v1/activity_service";
import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service"; import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
interface Props { interface Props {
@ -58,7 +58,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
return ( return (
<div className="w-full flex flex-row justify-start items-start gap-3"> <div className="w-full flex flex-row justify-start items-start gap-3">
<div <div
className={clsx( className={cn(
"shrink-0 mt-2 p-2 rounded-full border", "shrink-0 mt-2 p-2 rounded-full border",
inbox.status === Inbox_Status.UNREAD inbox.status === Inbox_Status.UNREAD
? "border-blue-600 text-blue-600 bg-blue-50 dark:bg-zinc-800" ? "border-blue-600 text-blue-600 bg-blue-50 dark:bg-zinc-800"
@ -70,7 +70,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
</Tooltip> </Tooltip>
</div> </div>
<div <div
className={clsx( className={cn(
"border w-full p-2 px-3 rounded-lg flex flex-col justify-start items-start gap-1 dark:border-zinc-700 hover:bg-gray-100 dark:hover:bg-zinc-700", "border w-full p-2 px-3 rounded-lg flex flex-col justify-start items-start gap-1 dark:border-zinc-700 hover:bg-gray-100 dark:hover:bg-zinc-700",
inbox.status !== Inbox_Status.UNREAD && "opacity-60", inbox.status !== Inbox_Status.UNREAD && "opacity-60",
)} )}

@ -1,5 +1,4 @@
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy"; import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import clsx from "clsx";
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import { import {
ArchiveIcon, ArchiveIcon,
@ -20,6 +19,7 @@ import { useMemoStore, useUserStatsStore } from "@/store/v1";
import { State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { NodeType } from "@/types/proto/api/v1/markdown_service"; import { NodeType } from "@/types/proto/api/v1/markdown_service";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { memoLink } from "@/utils/memo"; import { memoLink } from "@/utils/memo";
@ -166,7 +166,7 @@ const MemoActionMenu = (props: Props) => {
return ( return (
<Dropdown> <Dropdown>
<MenuButton slots={{ root: "div" }}> <MenuButton slots={{ root: "div" }}>
<span className={clsx("flex justify-center items-center rounded-full hover:opacity-70", props.className)}> <span className={cn("flex justify-center items-center rounded-full hover:opacity-70", props.className)}>
<MoreVerticalIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" /> <MoreVerticalIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
</span> </span>
</MenuButton> </MenuButton>

@ -1,9 +1,9 @@
import clsx from "clsx";
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import hljs from "highlight.js"; import hljs from "highlight.js";
import { CopyIcon } from "lucide-react"; import { CopyIcon } from "lucide-react";
import { useCallback, useMemo } from "react"; import { useCallback, useMemo } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { cn } from "@/utils";
import MermaidBlock from "./MermaidBlock"; import MermaidBlock from "./MermaidBlock";
import { BaseProps } from "./types"; import { BaseProps } from "./types";
@ -66,9 +66,9 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
</div> </div>
<div className="overflow-auto"> <div className="overflow-auto">
<pre className={clsx("no-wrap overflow-auto", "w-full p-2 bg-amber-50 dark:bg-zinc-700 relative")}> <pre className={cn("no-wrap overflow-auto", "w-full p-2 bg-amber-50 dark:bg-zinc-700 relative")}>
<code <code
className={clsx(`language-${formatedLanguage}`, "block text-sm leading-5")} className={cn(`language-${formatedLanguage}`, "block text-sm leading-5")}
dangerouslySetInnerHTML={{ __html: highlightedCode }} dangerouslySetInnerHTML={{ __html: highlightedCode }}
></code> ></code>
</pre> </pre>

@ -1,4 +1,3 @@
import clsx from "clsx";
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import { ArrowUpRightIcon } from "lucide-react"; import { ArrowUpRightIcon } from "lucide-react";
import { useContext, useEffect } from "react"; import { useContext, useEffect } from "react";
@ -7,6 +6,7 @@ import { Link } from "react-router-dom";
import MemoResourceListView from "@/components/MemoResourceListView"; import MemoResourceListView from "@/components/MemoResourceListView";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { extractMemoIdFromName, useMemoStore } from "@/store/v1"; import { extractMemoIdFromName, useMemoStore } from "@/store/v1";
import { cn } from "@/utils";
import { memoLink } from "@/utils/memo"; import { memoLink } from "@/utils/memo";
import MemoContent from ".."; import MemoContent from "..";
import { RendererContext } from "../types"; import { RendererContext } from "../types";
@ -45,7 +45,7 @@ const EmbeddedMemo = ({ resourceId: uid, params: paramsStr }: Props) => {
// Add the memo to the set of embedded memos. This is used to prevent infinite loops when a memo embeds itself. // Add the memo to the set of embedded memos. This is used to prevent infinite loops when a memo embeds itself.
context.embeddedMemos.add(memoName); context.embeddedMemos.add(memoName);
const contentNode = useSnippet ? ( const contentNode = useSnippet ? (
<div className={clsx("text-gray-800 dark:text-gray-400", inlineMode ? "" : "line-clamp-3")}>{memo.snippet}</div> <div className={cn("text-gray-800 dark:text-gray-400", inlineMode ? "" : "line-clamp-3")}>{memo.snippet}</div>
) : ( ) : (
<> <>
<MemoContent <MemoContent

@ -1,8 +1,8 @@
import clsx from "clsx";
import { useEffect } from "react"; import { useEffect } from "react";
import MemoResourceListView from "@/components/MemoResourceListView"; import MemoResourceListView from "@/components/MemoResourceListView";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useResourceStore } from "@/store/v1"; import { useResourceStore } from "@/store/v1";
import { cn } from "@/utils";
import Error from "./Error"; import Error from "./Error";
interface Props { interface Props {
@ -53,7 +53,7 @@ const EmbeddedResource = ({ resourceId: uid, params: paramsStr }: Props) => {
} }
return ( return (
<div className={clsx("max-w-full", getAdditionalClassNameWithParams(params))}> <div className={cn("max-w-full", getAdditionalClassNameWithParams(params))}>
<MemoResourceListView resources={[resource]} /> <MemoResourceListView resources={[resource]} />
</div> </div>
); );

@ -1,7 +1,7 @@
import clsx from "clsx";
import { head } from "lodash-es"; import { head } from "lodash-es";
import React from "react"; import React from "react";
import { ListNode_Kind, Node, NodeType } from "@/types/proto/api/v1/markdown_service"; import { ListNode_Kind, Node, NodeType } from "@/types/proto/api/v1/markdown_service";
import { cn } from "@/utils";
import Renderer from "./Renderer"; import Renderer from "./Renderer";
interface Props { interface Props {
@ -43,7 +43,7 @@ const List: React.FC<Props> = ({ kind, indent, children }: Props) => {
return React.createElement( return React.createElement(
getListContainer(), getListContainer(),
{ {
className: clsx( className: cn(
`list-inside ${kind === ListNode_Kind.ORDERED ? "list-decimal" : kind === ListNode_Kind.UNORDERED ? "list-disc" : "list-none"}`, `list-inside ${kind === ListNode_Kind.ORDERED ? "list-decimal" : kind === ListNode_Kind.UNORDERED ? "list-disc" : "list-none"}`,
indent > 0 ? `pl-${2 * indent}` : "", indent > 0 ? `pl-${2 * indent}` : "",
), ),

@ -1,6 +1,6 @@
import TeX from "@matejmazur/react-katex"; import TeX from "@matejmazur/react-katex";
import clsx from "clsx";
import "katex/dist/katex.min.css"; import "katex/dist/katex.min.css";
import { cn } from "@/utils";
interface Props { interface Props {
content: string; content: string;
@ -8,7 +8,7 @@ interface Props {
} }
const Math: React.FC<Props> = ({ content, block }: Props) => { const Math: React.FC<Props> = ({ content, block }: Props) => {
return <TeX className={clsx("max-w-full", block ? "w-full block" : "inline text-sm")} block={block} math={content}></TeX>; return <TeX className={cn("max-w-full", block ? "w-full block" : "inline text-sm")} block={block} math={content}></TeX>;
}; };
export default Math; export default Math;

@ -1,5 +1,5 @@
import clsx from "clsx";
import { useState } from "react"; import { useState } from "react";
import { cn } from "@/utils";
interface Props { interface Props {
content: string; content: string;
@ -10,10 +10,10 @@ const Spoiler: React.FC<Props> = ({ content }: Props) => {
return ( return (
<span <span
className={clsx("inline cursor-pointer select-none", isRevealed ? "" : "bg-gray-200 dark:bg-zinc-700")} className={cn("inline cursor-pointer select-none", isRevealed ? "" : "bg-gray-200 dark:bg-zinc-700")}
onClick={() => setIsRevealed(!isRevealed)} onClick={() => setIsRevealed(!isRevealed)}
> >
<span className={clsx(isRevealed ? "opacity-100" : "opacity-0")}>{content}</span> <span className={cn(isRevealed ? "opacity-100" : "opacity-0")}>{content}</span>
</span> </span>
); );
}; };

@ -1,9 +1,9 @@
import clsx from "clsx";
import { useContext } from "react"; import { useContext } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import useNavigateTo from "@/hooks/useNavigateTo"; import useNavigateTo from "@/hooks/useNavigateTo";
import { Routes } from "@/router"; import { Routes } from "@/router";
import { stringifyFilters, useMemoFilterStore } from "@/store/v1"; import { stringifyFilters, useMemoFilterStore } from "@/store/v1";
import { cn } from "@/utils";
import { RendererContext } from "./types"; import { RendererContext } from "./types";
interface Props { interface Props {
@ -44,10 +44,7 @@ const Tag: React.FC<Props> = ({ content }: Props) => {
return ( return (
<span <span
className={clsx( className={cn("inline-block w-auto text-blue-600 dark:text-blue-400", context.disableFilter ? "" : "cursor-pointer hover:opacity-80")}
"inline-block w-auto text-blue-600 dark:text-blue-400",
context.disableFilter ? "" : "cursor-pointer hover:opacity-80",
)}
onClick={handleTagClick} onClick={handleTagClick}
> >
#{content} #{content}

@ -1,9 +1,9 @@
import { Checkbox } from "@usememos/mui"; import { Checkbox } from "@usememos/mui";
import clsx from "clsx";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { markdownServiceClient } from "@/grpcweb"; import { markdownServiceClient } from "@/grpcweb";
import { useMemoStore } from "@/store/v1"; import { useMemoStore } from "@/store/v1";
import { Node, TaskListItemNode } from "@/types/proto/api/v1/markdown_service"; import { Node, TaskListItemNode } from "@/types/proto/api/v1/markdown_service";
import { cn } from "@/utils";
import Renderer from "./Renderer"; import Renderer from "./Renderer";
import { RendererContext } from "./types"; import { RendererContext } from "./types";
@ -39,11 +39,11 @@ const TaskListItem: React.FC<Props> = ({ node, complete, children }: Props) => {
}; };
return ( return (
<li className={clsx("w-full grid grid-cols-[24px_1fr]")}> <li className={cn("w-full grid grid-cols-[24px_1fr]")}>
<span className="w-6 h-6 flex justify-start items-center"> <span className="w-6 h-6 flex justify-start items-center">
<Checkbox size="sm" checked={checked} disabled={context.readonly} onChange={(e) => handleCheckboxChange(e.target.checked)} /> <Checkbox size="sm" checked={checked} disabled={context.readonly} onChange={(e) => handleCheckboxChange(e.target.checked)} />
</span> </span>
<p className={clsx(complete && "line-through opacity-80")}> <p className={cn(complete && "line-through opacity-80")}>
{children.map((child, index) => ( {children.map((child, index) => (
<Renderer key={`${child.type}-${index}`} index={String(index)} node={child} /> <Renderer key={`${child.type}-${index}`} index={String(index)} node={child} />
))} ))}

@ -1,8 +1,8 @@
import clsx from "clsx";
import { memo, useEffect, useRef, useState } from "react"; import { memo, useEffect, useRef, useState } from "react";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoStore } from "@/store/v1"; import { useMemoStore } from "@/store/v1";
import { Node, NodeType } from "@/types/proto/api/v1/markdown_service"; import { Node, NodeType } from "@/types/proto/api/v1/markdown_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { isSuperUser } from "@/utils/user"; import { isSuperUser } from "@/utils/user";
import Renderer from "./Renderer"; import Renderer from "./Renderer";
@ -86,7 +86,7 @@ const MemoContent: React.FC<Props> = (props: Props) => {
<div className={`w-full flex flex-col justify-start items-start text-gray-800 dark:text-gray-400 ${className || ""}`}> <div className={`w-full flex flex-col justify-start items-start text-gray-800 dark:text-gray-400 ${className || ""}`}>
<div <div
ref={memoContentContainerRef} ref={memoContentContainerRef}
className={clsx( className={cn(
"relative w-full max-w-full word-break text-base leading-snug space-y-2 whitespace-pre-wrap", "relative w-full max-w-full word-break text-base leading-snug space-y-2 whitespace-pre-wrap",
showCompactMode == "ALL" && "line-clamp-6 max-h-60", showCompactMode == "ALL" && "line-clamp-6 max-h-60",
contentClassName, contentClassName,

@ -1,8 +1,8 @@
import clsx from "clsx";
import { isEqual } from "lodash-es"; import { isEqual } from "lodash-es";
import { CheckCircleIcon, Code2Icon, HashIcon, LinkIcon } from "lucide-react"; import { CheckCircleIcon, Code2Icon, HashIcon, LinkIcon } from "lucide-react";
import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service"; import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Memo, MemoProperty } from "@/types/proto/api/v1/memo_service"; import { Memo, MemoProperty } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import MemoRelationForceGraph from "../MemoRelationForceGraph"; import MemoRelationForceGraph from "../MemoRelationForceGraph";
@ -20,10 +20,7 @@ const MemoDetailSidebar = ({ memo, className, parentPage }: Props) => {
return ( return (
<aside <aside
className={clsx( className={cn("relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start", className)}
"relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start",
className,
)}
> >
<div className="flex flex-col justify-start items-start w-full px-1 gap-2 h-auto shrink-0 flex-nowrap hide-scrollbar"> <div className="flex flex-col justify-start items-start w-full px-1 gap-2 h-auto shrink-0 flex-nowrap hide-scrollbar">
{shouldShowRelationGraph && ( {shouldShowRelationGraph && (
@ -95,7 +92,7 @@ const MemoDetailSidebar = ({ memo, className, parentPage }: Props) => {
className="shrink-0 w-auto max-w-full text-sm rounded-md leading-6 flex flex-row justify-start items-center select-none hover:opacity-80 text-gray-600 dark:text-gray-400 dark:border-zinc-800" className="shrink-0 w-auto max-w-full text-sm rounded-md leading-6 flex flex-row justify-start items-center select-none hover:opacity-80 text-gray-600 dark:text-gray-400 dark:border-zinc-800"
> >
<HashIcon className="group-hover:hidden w-4 h-auto shrink-0 opacity-40" /> <HashIcon className="group-hover:hidden w-4 h-auto shrink-0 opacity-40" />
<div className={clsx("inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]")}> <div className={cn("inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]")}>
<span className="truncate dark:opacity-80">{tag}</span> <span className="truncate dark:opacity-80">{tag}</span>
</div> </div>
</div> </div>

@ -1,7 +1,7 @@
import { Option, Select } from "@mui/joy"; import { Option, Select } from "@mui/joy";
import clsx from "clsx";
import { Settings2Icon } from "lucide-react"; import { Settings2Icon } from "lucide-react";
import { useMemoFilterStore } from "@/store/v1"; import { useMemoFilterStore } from "@/store/v1";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover"; import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
@ -17,7 +17,7 @@ const MemoDisplaySettingMenu = ({ className }: Props) => {
return ( return (
<Popover> <Popover>
<PopoverTrigger <PopoverTrigger
className={clsx(className, isApplying ? "text-teal-600 bg-teal-50 dark:text-teal-500 dark:bg-teal-900 rounded-sm" : "opacity-40")} className={cn(className, isApplying ? "text-teal-600 bg-teal-50 dark:text-teal-500 dark:bg-teal-900 rounded-sm" : "opacity-40")}
> >
<Settings2Icon className="w-4 h-auto shrink-0" /> <Settings2Icon className="w-4 h-auto shrink-0" />
</PopoverTrigger> </PopoverTrigger>

@ -1,9 +1,9 @@
import clsx from "clsx";
import Fuse from "fuse.js"; import Fuse from "fuse.js";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import getCaretCoordinates from "textarea-caret"; import getCaretCoordinates from "textarea-caret";
import OverflowTip from "@/components/kit/OverflowTip"; import OverflowTip from "@/components/kit/OverflowTip";
import { useUserStatsTags } from "@/store/v1"; import { useUserStatsTags } from "@/store/v1";
import { cn } from "@/utils";
import { EditorRefActions } from "."; import { EditorRefActions } from ".";
type Props = { type Props = {
@ -110,7 +110,7 @@ const TagSuggestions = ({ editorRef, editorActions }: Props) => {
<div <div
key={tag} key={tag}
onMouseDown={() => autocomplete(tag)} onMouseDown={() => autocomplete(tag)}
className={clsx( className={cn(
"rounded p-1 px-2 w-full truncate text-sm dark:text-gray-300 cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-800", "rounded p-1 px-2 w-full truncate text-sm dark:text-gray-300 cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-800",
i === selected ? "bg-zinc-300 dark:bg-zinc-600" : "", i === selected ? "bg-zinc-300 dark:bg-zinc-600" : "",
)} )}

@ -1,8 +1,8 @@
import clsx from "clsx";
import { last } from "lodash-es"; import { last } from "lodash-es";
import { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; import { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
import { markdownServiceClient } from "@/grpcweb"; import { markdownServiceClient } from "@/grpcweb";
import { NodeType, OrderedListItemNode, TaskListItemNode, UnorderedListItemNode } from "@/types/proto/api/v1/markdown_service"; import { NodeType, OrderedListItemNode, TaskListItemNode, UnorderedListItemNode } from "@/types/proto/api/v1/markdown_service";
import { cn } from "@/utils";
import TagSuggestions from "./TagSuggestions"; import TagSuggestions from "./TagSuggestions";
export interface EditorRefActions { export interface EditorRefActions {
@ -187,10 +187,7 @@ const Editor = forwardRef(function Editor(props: Props, ref: React.ForwardedRef<
return ( return (
<div <div
className={clsx( className={cn("flex flex-col justify-start items-start relative w-full h-auto max-h-[50vh] bg-inherit dark:text-gray-300", className)}
"flex flex-col justify-start items-start relative w-full h-auto max-h-[50vh] bg-inherit dark:text-gray-300",
className,
)}
> >
<textarea <textarea
className="w-full h-full my-1 text-base resize-none overflow-x-hidden overflow-y-auto bg-transparent outline-none whitespace-pre-wrap word-break" className="w-full h-full my-1 text-base resize-none overflow-x-hidden overflow-y-auto bg-transparent outline-none whitespace-pre-wrap word-break"

@ -75,15 +75,15 @@ const MemoFilters = () => {
return ( return (
<div className="w-full mb-2 flex flex-row justify-start items-start gap-2"> <div className="w-full mb-2 flex flex-row justify-start items-start gap-2">
<span className="flex flex-row items-center gap-0.5 text-gray-500 text-sm leading-6 border border-transparent"> <span className="flex flex-row items-center gap-0.5 text-gray-500 text-sm leading-7 border border-transparent">
<FilterIcon className="w-4 h-auto opacity-60 inline" /> <FilterIcon className="w-4 h-auto opacity-60 inline" />
{t("memo.filters")} {t("memo.filters")}
</span> </span>
<div className="flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6"> <div className="flex flex-row justify-start items-center flex-wrap gap-x-2 gap-y-1 leading-7 h-7">
{filters.map((filter) => ( {filters.map((filter) => (
<div <div
key={getMemoFilterKey(filter)} key={getMemoFilterKey(filter)}
className="flex flex-row items-center gap-1 bg-white dark:bg-zinc-800 border dark:border-zinc-700 pl-1.5 pr-1 rounded-md hover:line-through cursor-pointer" className="w-auto h-full flex flex-row items-center gap-1 bg-white dark:bg-zinc-800 border dark:border-zinc-700 pl-1.5 pr-1 rounded-md hover:line-through cursor-pointer"
onClick={() => memoFilterStore.removeFilter((f) => isEqual(f, filter))} onClick={() => memoFilterStore.removeFilter((f) => isEqual(f, filter))}
> >
<FactorIcon className="w-4 h-auto text-gray-500 dark:text-gray-400 opacity-60" factor={filter.factor} /> <FactorIcon className="w-4 h-auto text-gray-500 dark:text-gray-400 opacity-60" factor={filter.factor} />

@ -1,10 +1,10 @@
import { useColorScheme } from "@mui/joy"; import { useColorScheme } from "@mui/joy";
import clsx from "clsx";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import ForceGraph2D, { ForceGraphMethods, LinkObject, NodeObject } from "react-force-graph-2d"; import ForceGraph2D, { ForceGraphMethods, LinkObject, NodeObject } from "react-force-graph-2d";
import useNavigateTo from "@/hooks/useNavigateTo"; import useNavigateTo from "@/hooks/useNavigateTo";
import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service"; import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
import { memoLink } from "@/utils/memo"; import { memoLink } from "@/utils/memo";
import { LinkType, NodeType } from "./types"; import { LinkType, NodeType } from "./types";
import { convertMemoRelationsToGraphData } from "./utils"; import { convertMemoRelationsToGraphData } from "./utils";
@ -40,7 +40,7 @@ const MemoRelationForceGraph = ({ className, memo, parentPage }: Props) => {
}; };
return ( return (
<div ref={containerRef} className={clsx("dark:opacity-80", className)}> <div ref={containerRef} className={cn("dark:opacity-80", className)}>
<ForceGraph2D <ForceGraph2D
ref={graphRef} ref={graphRef}
width={graphSize.width} width={graphSize.width}

@ -1,9 +1,9 @@
import clsx from "clsx";
import { LinkIcon, MilestoneIcon } from "lucide-react"; import { LinkIcon, MilestoneIcon } from "lucide-react";
import { memo, useState } from "react"; import { memo, useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { MemoRelation } from "@/types/proto/api/v1/memo_relation_service"; import { MemoRelation } from "@/types/proto/api/v1/memo_relation_service";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
interface Props { interface Props {
memo: Memo; memo: Memo;
@ -32,7 +32,7 @@ const MemoRelationListView = (props: Props) => {
<div className="w-full flex flex-row justify-start items-center mb-1 gap-3 opacity-60"> <div className="w-full flex flex-row justify-start items-center mb-1 gap-3 opacity-60">
{referencingMemoList.length > 0 && ( {referencingMemoList.length > 0 && (
<button <button
className={clsx( className={cn(
"w-auto flex flex-row justify-start items-center text-xs gap-0.5 text-gray-500", "w-auto flex flex-row justify-start items-center text-xs gap-0.5 text-gray-500",
selectedTab === "referencing" && "text-gray-800 dark:text-gray-400", selectedTab === "referencing" && "text-gray-800 dark:text-gray-400",
)} )}
@ -45,7 +45,7 @@ const MemoRelationListView = (props: Props) => {
)} )}
{referencedMemoList.length > 0 && ( {referencedMemoList.length > 0 && (
<button <button
className={clsx( className={cn(
"w-auto flex flex-row justify-start items-center text-xs gap-0.5 text-gray-500", "w-auto flex flex-row justify-start items-center text-xs gap-0.5 text-gray-500",
selectedTab === "referenced" && "text-gray-800 dark:text-gray-400", selectedTab === "referenced" && "text-gray-800 dark:text-gray-400",
)} )}

@ -1,5 +1,4 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { BookmarkIcon, MessageCircleMoreIcon } from "lucide-react"; import { BookmarkIcon, MessageCircleMoreIcon } from "lucide-react";
import { memo, useCallback, useRef, useState } from "react"; import { memo, useCallback, useRef, useState } from "react";
import { Link, useLocation } from "react-router-dom"; import { Link, useLocation } from "react-router-dom";
@ -12,6 +11,7 @@ import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Memo, Visibility } from "@/types/proto/api/v1/memo_service"; import { Memo, Visibility } from "@/types/proto/api/v1/memo_service";
import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service"; import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { convertVisibilityToString, memoLink } from "@/utils/memo"; import { convertVisibilityToString, memoLink } from "@/utils/memo";
import { isSuperUser } from "@/utils/user"; import { isSuperUser } from "@/utils/user";
@ -125,7 +125,7 @@ const MemoView: React.FC<Props> = (props: Props) => {
return ( return (
<div <div
className={clsx( className={cn(
"group relative flex flex-col justify-start items-start w-full px-4 py-3 mb-2 gap-2 bg-white dark:bg-zinc-800 rounded-lg border border-white dark:border-zinc-800 hover:border-gray-200 dark:hover:border-zinc-700", "group relative flex flex-col justify-start items-start w-full px-4 py-3 mb-2 gap-2 bg-white dark:bg-zinc-800 rounded-lg border border-white dark:border-zinc-800 hover:border-gray-200 dark:hover:border-zinc-700",
props.showPinned && memo.pinned && "border-gray-200 border dark:border-zinc-700", props.showPinned && memo.pinned && "border-gray-200 border dark:border-zinc-700",
className, className,
@ -188,7 +188,7 @@ const MemoView: React.FC<Props> = (props: Props) => {
</div> </div>
{!isInMemoDetailPage && (workspaceMemoRelatedSetting.enableComment || commentAmount > 0) && ( {!isInMemoDetailPage && (workspaceMemoRelatedSetting.enableComment || commentAmount > 0) && (
<Link <Link
className={clsx( className={cn(
"flex flex-row justify-start items-center hover:opacity-70", "flex flex-row justify-start items-center hover:opacity-70",
commentAmount === 0 && "invisible group-hover:visible", commentAmount === 0 && "invisible group-hover:visible",
)} )}

@ -1,9 +1,9 @@
import clsx from "clsx";
import useWindowScroll from "react-use/lib/useWindowScroll"; import useWindowScroll from "react-use/lib/useWindowScroll";
import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { useWorkspaceSettingStore } from "@/store/v1"; import { useWorkspaceSettingStore } from "@/store/v1";
import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service"; import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { cn } from "@/utils";
import NavigationDrawer from "./NavigationDrawer"; import NavigationDrawer from "./NavigationDrawer";
interface Props { interface Props {
@ -21,7 +21,7 @@ const MobileHeader = (props: Props) => {
return ( return (
<div <div
className={clsx( className={cn(
"sticky top-0 pt-3 pb-2 sm:pt-2 px-4 sm:px-6 sm:mb-1 bg-zinc-100 dark:bg-zinc-900 bg-opacity-80 backdrop-blur-lg flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-1", "sticky top-0 pt-3 pb-2 sm:pt-2 px-4 sm:px-6 sm:mb-1 bg-zinc-100 dark:bg-zinc-900 bg-opacity-80 backdrop-blur-lg flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-1",
offsetTop > 0 && "shadow-md", offsetTop > 0 && "shadow-md",
className, className,

@ -1,5 +1,4 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { ArchiveIcon, BellIcon, Globe2Icon, HomeIcon, LogInIcon, PaperclipIcon, SettingsIcon, SmileIcon, User2Icon } from "lucide-react"; import { ArchiveIcon, BellIcon, Globe2Icon, HomeIcon, LogInIcon, PaperclipIcon, SettingsIcon, SmileIcon, User2Icon } from "lucide-react";
import { useEffect } from "react"; import { useEffect } from "react";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
@ -7,6 +6,7 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import { Routes } from "@/router"; import { Routes } from "@/router";
import { useInboxStore } from "@/store/v1"; import { useInboxStore } from "@/store/v1";
import { Inbox_Status } from "@/types/proto/api/v1/inbox_service"; import { Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import UserBanner from "./UserBanner"; import UserBanner from "./UserBanner";
@ -116,14 +116,14 @@ const Navigation = (props: Props) => {
return ( return (
<header <header
className={clsx("w-full h-full overflow-auto flex flex-col justify-start items-start py-4 md:pt-6 z-30 hide-scrollbar", className)} className={cn("w-full h-full overflow-auto flex flex-col justify-start items-start py-4 md:pt-6 z-30 hide-scrollbar", className)}
> >
<UserBanner collapsed={collapsed} /> <UserBanner collapsed={collapsed} />
<div className="w-full px-1 py-2 flex flex-col justify-start items-start shrink-0 space-y-2"> <div className="w-full px-1 py-2 flex flex-col justify-start items-start shrink-0 space-y-2">
{navLinks.map((navLink) => ( {navLinks.map((navLink) => (
<NavLink <NavLink
className={({ isActive }) => className={({ isActive }) =>
clsx( cn(
"px-2 py-2 rounded-2xl border flex flex-row items-center text-lg text-gray-800 dark:text-gray-400 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-700 dark:hover:bg-zinc-800", "px-2 py-2 rounded-2xl border flex flex-row items-center text-lg text-gray-800 dark:text-gray-400 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-700 dark:hover:bg-zinc-800",
collapsed ? "" : "w-full px-4", collapsed ? "" : "w-full px-4",
isActive ? "bg-white drop-shadow-sm dark:bg-zinc-800 border-gray-200 dark:border-zinc-700" : "border-transparent", isActive ? "bg-white drop-shadow-sm dark:bg-zinc-800 border-gray-200 dark:border-zinc-700" : "border-transparent",

@ -1,5 +1,4 @@
import { Dropdown, Menu, MenuButton } from "@mui/joy"; import { Dropdown, Menu, MenuButton } from "@mui/joy";
import clsx from "clsx";
import { SmilePlusIcon } from "lucide-react"; import { SmilePlusIcon } from "lucide-react";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import useClickAway from "react-use/lib/useClickAway"; import useClickAway from "react-use/lib/useClickAway";
@ -9,6 +8,7 @@ import { useMemoStore, useWorkspaceSettingStore } from "@/store/v1";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service"; import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { cn } from "@/utils";
interface Props { interface Props {
memo: Memo; memo: Memo;
@ -63,7 +63,7 @@ const ReactionSelector = (props: Props) => {
<Dropdown open={open} onOpenChange={(_, isOpen) => setOpen(isOpen)}> <Dropdown open={open} onOpenChange={(_, isOpen) => setOpen(isOpen)}>
<MenuButton slots={{ root: "div" }}> <MenuButton slots={{ root: "div" }}>
<span <span
className={clsx("h-7 w-7 flex justify-center items-center rounded-full border dark:border-zinc-700 hover:opacity-70", className)} className={cn("h-7 w-7 flex justify-center items-center rounded-full border dark:border-zinc-700 hover:opacity-70", className)}
> >
<SmilePlusIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" /> <SmilePlusIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
</span> </span>
@ -75,7 +75,7 @@ const ReactionSelector = (props: Props) => {
return ( return (
<span <span
key={reactionType} key={reactionType}
className={clsx( className={cn(
"inline-flex w-auto text-base cursor-pointer rounded px-1 text-gray-500 dark:text-gray-400 hover:opacity-80", "inline-flex w-auto text-base cursor-pointer rounded px-1 text-gray-500 dark:text-gray-400 hover:opacity-80",
hasReacted(reactionType) && "bg-blue-100 dark:bg-zinc-800", hasReacted(reactionType) && "bg-blue-100 dark:bg-zinc-800",
)} )}

@ -1,11 +1,11 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { memoServiceClient } from "@/grpcweb"; import { memoServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoStore } from "@/store/v1"; import { useMemoStore } from "@/store/v1";
import { State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { User } from "@/types/proto/api/v1/user_service"; import { User } from "@/types/proto/api/v1/user_service";
import { cn } from "@/utils";
interface Props { interface Props {
memo: Memo; memo: Memo;
@ -67,7 +67,7 @@ const ReactionView = (props: Props) => {
return ( return (
<Tooltip title={stringifyUsers(users, reactionType)} placement="top"> <Tooltip title={stringifyUsers(users, reactionType)} placement="top">
<div <div
className={clsx( className={cn(
"h-7 border px-2 py-0.5 rounded-full flex flex-row justify-center items-center gap-1 dark:border-zinc-700", "h-7 border px-2 py-0.5 rounded-full flex flex-row justify-center items-center gap-1 dark:border-zinc-700",
"text-sm text-gray-600 dark:text-gray-400", "text-sm text-gray-600 dark:text-gray-400",
currentUser && !readonly && "cursor-pointer", currentUser && !readonly && "cursor-pointer",

@ -1,4 +1,3 @@
import clsx from "clsx";
import { import {
BinaryIcon, BinaryIcon,
BookIcon, BookIcon,
@ -12,6 +11,7 @@ import {
} from "lucide-react"; } from "lucide-react";
import React from "react"; import React from "react";
import { Resource } from "@/types/proto/api/v1/resource_service"; import { Resource } from "@/types/proto/api/v1/resource_service";
import { cn } from "@/utils";
import { getResourceType, getResourceUrl } from "@/utils/resource"; import { getResourceType, getResourceUrl } from "@/utils/resource";
import showPreviewImageDialog from "./PreviewImageDialog"; import showPreviewImageDialog from "./PreviewImageDialog";
import SquareDiv from "./kit/SquareDiv"; import SquareDiv from "./kit/SquareDiv";
@ -26,7 +26,7 @@ const ResourceIcon = (props: Props) => {
const { resource } = props; const { resource } = props;
const resourceType = getResourceType(resource); const resourceType = getResourceType(resource);
const resourceUrl = getResourceUrl(resource); const resourceUrl = getResourceUrl(resource);
const className = clsx("w-full h-auto", props.className); const className = cn("w-full h-auto", props.className);
const strokeWidth = props.strokeWidth; const strokeWidth = props.strokeWidth;
const previewResource = () => { const previewResource = () => {
@ -35,7 +35,7 @@ const ResourceIcon = (props: Props) => {
if (resourceType === "image/*") { if (resourceType === "image/*") {
return ( return (
<SquareDiv className={clsx(className, "flex items-center justify-center overflow-clip")}> <SquareDiv className={cn(className, "flex items-center justify-center overflow-clip")}>
<img <img
className="min-w-full min-h-full object-cover" className="min-w-full min-h-full object-cover"
src={resource.externalLink ? resourceUrl : resourceUrl + "?thumbnail=true"} src={resource.externalLink ? resourceUrl : resourceUrl + "?thumbnail=true"}
@ -73,7 +73,7 @@ const ResourceIcon = (props: Props) => {
}; };
return ( return (
<div onClick={previewResource} className={clsx(className, "max-w-[4rem] opacity-50")}> <div onClick={previewResource} className={cn(className, "max-w-[4rem] opacity-50")}>
{getResourceIcon()} {getResourceIcon()}
</div> </div>
); );

@ -1,5 +1,4 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { countBy } from "lodash-es"; import { countBy } from "lodash-es";
import { CheckCircleIcon, ChevronDownIcon, ChevronUpIcon, Code2Icon, LinkIcon, ListTodoIcon } from "lucide-react"; import { CheckCircleIcon, ChevronDownIcon, ChevronUpIcon, Code2Icon, LinkIcon, ListTodoIcon } from "lucide-react";
@ -8,6 +7,7 @@ import useAsyncEffect from "@/hooks/useAsyncEffect";
import i18n from "@/i18n"; import i18n from "@/i18n";
import { useMemoFilterStore, useUserStatsStore } from "@/store/v1"; import { useMemoFilterStore, useUserStatsStore } from "@/store/v1";
import { UserStats_MemoTypeStats } from "@/types/proto/api/v1/user_service"; import { UserStats_MemoTypeStats } from "@/types/proto/api/v1/user_service";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import ActivityCalendar from "./ActivityCalendar"; import ActivityCalendar from "./ActivityCalendar";
@ -42,7 +42,7 @@ const StatisticsView = () => {
}; };
return ( return (
<div className="group w-full mt-2 py-2 space-y-1 text-gray-500 dark:text-gray-400"> <div className="group w-full mt-4 space-y-1 text-gray-500 dark:text-gray-400">
<div className="w-full mb-1 flex flex-row justify-between items-center gap-1"> <div className="w-full mb-1 flex flex-row justify-between items-center gap-1">
<div className="relative text-sm font-medium inline-flex flex-row items-center w-auto dark:text-gray-400 truncate"> <div className="relative text-sm font-medium inline-flex flex-row items-center w-auto dark:text-gray-400 truncate">
<span className="truncate"> <span className="truncate">
@ -74,7 +74,7 @@ const StatisticsView = () => {
</div> </div>
<div className="pt-1 w-full flex flex-row justify-start items-center gap-x-2 gap-y-1 flex-wrap"> <div className="pt-1 w-full flex flex-row justify-start items-center gap-x-2 gap-y-1 flex-wrap">
<div <div
className={clsx("w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center")} className={cn("w-auto border dark:border-zinc-800 pl-1.5 pr-2 py-0.5 rounded-md flex justify-between items-center")}
onClick={() => memoFilterStore.addFilter({ factor: "property.hasLink", value: "" })} onClick={() => memoFilterStore.addFilter({ factor: "property.hasLink", value: "" })}
> >
<div className="w-auto flex justify-start items-center mr-1"> <div className="w-auto flex justify-start items-center mr-1">
@ -84,7 +84,7 @@ const StatisticsView = () => {
<span className="text-sm truncate">{memoTypeStats.linkCount}</span> <span className="text-sm truncate">{memoTypeStats.linkCount}</span>
</div> </div>
<div <div
className={clsx("w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center")} className={cn("w-auto border dark:border-zinc-800 pl-1.5 pr-2 py-0.5 rounded-md flex justify-between items-center")}
onClick={() => memoFilterStore.addFilter({ factor: "property.hasTaskList", value: "" })} onClick={() => memoFilterStore.addFilter({ factor: "property.hasTaskList", value: "" })}
> >
<div className="w-auto flex justify-start items-center mr-1"> <div className="w-auto flex justify-start items-center mr-1">
@ -104,7 +104,7 @@ const StatisticsView = () => {
)} )}
</div> </div>
<div <div
className={clsx("w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center")} className={cn("w-auto border dark:border-zinc-800 pl-1.5 pr-2 py-0.5 rounded-md flex justify-between items-center")}
onClick={() => memoFilterStore.addFilter({ factor: "property.hasCode", value: "" })} onClick={() => memoFilterStore.addFilter({ factor: "property.hasCode", value: "" })}
> >
<div className="w-auto flex justify-start items-center mr-1"> <div className="w-auto flex justify-start items-center mr-1">

@ -1,4 +1,4 @@
import clsx from "clsx"; import { cn } from "@/utils";
interface Props { interface Props {
avatarUrl?: string; avatarUrl?: string;
@ -8,7 +8,7 @@ interface Props {
const UserAvatar = (props: Props) => { const UserAvatar = (props: Props) => {
const { avatarUrl, className } = props; const { avatarUrl, className } = props;
return ( return (
<div className={clsx(`w-8 h-8 overflow-clip rounded-xl`, className)}> <div className={cn(`w-8 h-8 overflow-clip rounded-xl`, className)}>
<img <img
className="w-full h-auto shadow min-w-full min-h-full object-cover dark:opacity-80" className="w-full h-auto shadow min-w-full min-h-full object-cover dark:opacity-80"
src={avatarUrl || "/full-logo.webp"} src={avatarUrl || "/full-logo.webp"}

@ -1,5 +1,4 @@
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy"; import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import clsx from "clsx";
import { LogOutIcon, SmileIcon } from "lucide-react"; import { LogOutIcon, SmileIcon } from "lucide-react";
import { authServiceClient } from "@/grpcweb"; import { authServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
@ -8,6 +7,7 @@ import { Routes } from "@/router";
import { useWorkspaceSettingStore } from "@/store/v1"; import { useWorkspaceSettingStore } from "@/store/v1";
import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service"; import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import UserAvatar from "./UserAvatar"; import UserAvatar from "./UserAvatar";
@ -36,7 +36,7 @@ const UserBanner = (props: Props) => {
<Dropdown> <Dropdown>
<MenuButton disabled={!user} slots={{ root: "div" }}> <MenuButton disabled={!user} slots={{ root: "div" }}>
<div <div
className={clsx( className={cn(
"py-1 my-1 w-auto flex flex-row justify-start items-center cursor-pointer text-gray-800 dark:text-gray-400", "py-1 my-1 w-auto flex flex-row justify-start items-center cursor-pointer text-gray-800 dark:text-gray-400",
collapsed ? "px-1" : "px-3", collapsed ? "px-1" : "px-3",
)} )}

@ -1,6 +1,6 @@
import clsx from "clsx";
import { Globe2Icon, LockIcon, UsersIcon } from "lucide-react"; import { Globe2Icon, LockIcon, UsersIcon } from "lucide-react";
import { Visibility } from "@/types/proto/api/v1/memo_service"; import { Visibility } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
interface Props { interface Props {
visibility: Visibility; visibility: Visibility;
@ -21,7 +21,7 @@ const VisibilityIcon = (props: Props) => {
return null; return null;
} }
return <VIcon className={clsx("w-4 h-auto text-gray-500 dark:text-gray-400")} />; return <VIcon className={cn("w-4 h-auto text-gray-500 dark:text-gray-400")} />;
}; };
export default VisibilityIcon; export default VisibilityIcon;

@ -1,6 +1,6 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { useRef, useState, useEffect } from "react"; import { useRef, useState, useEffect } from "react";
import { cn } from "@/utils";
interface Props { interface Props {
children: React.ReactNode; children: React.ReactNode;
@ -21,7 +21,7 @@ const OverflowTip = ({ children, className }: Props) => {
return ( return (
<Tooltip title={children} placement="top" arrow disableHoverListener={!isOverflowed}> <Tooltip title={children} placement="top" arrow disableHoverListener={!isOverflowed}>
<div ref={textElementRef} className={clsx("truncate", className)}> <div ref={textElementRef} className={cn("truncate", className)}>
{children} {children}
</div> </div>
</Tooltip> </Tooltip>

@ -1,6 +1,6 @@
import * as PopoverPrimitive from "@radix-ui/react-popover"; import * as PopoverPrimitive from "@radix-ui/react-popover";
import clsx from "clsx";
import * as React from "react"; import * as React from "react";
import { cn } from "@/utils";
const Popover = PopoverPrimitive.Root; const Popover = PopoverPrimitive.Root;
@ -16,8 +16,8 @@ const PopoverContent = React.forwardRef<
ref={ref} ref={ref}
align={align} align={align}
sideOffset={sideOffset} sideOffset={sideOffset}
className={clsx( className={cn(
"z-[2000] w-auto rounded-md bg-white dark:bg-zinc-900 border dark:border-zinc-800 bg-popover p-2 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "z-[2000] w-auto rounded-md bg-white dark:bg-zinc-900 border dark:border-zinc-800 p-2 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className, className,
)} )}
{...props} {...props}

@ -1,6 +1,5 @@
import { Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import { Button } from "@usememos/mui"; import { Button } from "@usememos/mui";
import clsx from "clsx";
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import { Suspense, useEffect, useMemo, useState } from "react"; import { Suspense, useEffect, useMemo, useState } from "react";
import { Outlet, useLocation, useSearchParams } from "react-router-dom"; import { Outlet, useLocation, useSearchParams } from "react-router-dom";
@ -12,6 +11,7 @@ import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import Loading from "@/pages/Loading"; import Loading from "@/pages/Loading";
import { Routes } from "@/router"; import { Routes } from "@/router";
import { useMemoFilterStore } from "@/store/v1"; import { useMemoFilterStore } from "@/store/v1";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
const RootLayout = () => { const RootLayout = () => {
@ -47,18 +47,18 @@ const RootLayout = () => {
<Loading /> <Loading />
) : ( ) : (
<div className="w-full min-h-full"> <div className="w-full min-h-full">
<div className={clsx("w-full transition-all mx-auto flex flex-row justify-center items-start", collapsed ? "sm:pl-16" : "sm:pl-56")}> <div className={cn("w-full transition-all mx-auto flex flex-row justify-center items-start", collapsed ? "sm:pl-16" : "sm:pl-56")}>
{sm && ( {sm && (
<div <div
className={clsx( className={cn(
"group flex flex-col justify-start items-start fixed top-0 left-0 select-none border-r dark:border-zinc-800 h-full bg-zinc-50 dark:bg-zinc-800 dark:bg-opacity-40 transition-all hover:shadow-xl z-2", "group flex flex-col justify-start items-start fixed top-0 left-0 select-none border-r dark:border-zinc-800 h-full bg-zinc-50 dark:bg-zinc-800 dark:bg-opacity-40 transition-all hover:shadow-xl z-2",
collapsed ? "w-16 px-2" : "w-56 px-4", collapsed ? "w-16 px-2" : "w-56 px-4",
)} )}
> >
<Navigation className="!h-auto" collapsed={collapsed} /> <Navigation className="!h-auto" collapsed={collapsed} />
<div className={clsx("w-full grow h-auto flex flex-col justify-end", collapsed ? "items-center" : "items-start")}> <div className={cn("w-full grow h-auto flex flex-col justify-end", collapsed ? "items-center" : "items-start")}>
<div <div
className={clsx("hidden py-3 group-hover:flex flex-col justify-center items-center")} className={cn("hidden py-3 group-hover:flex flex-col justify-center items-center")}
onClick={() => setCollapsed(!collapsed)} onClick={() => setCollapsed(!collapsed)}
> >
{!collapsed ? ( {!collapsed ? (

@ -354,8 +354,8 @@
"workspace-section": { "workspace-section": {
"disallow-user-registration": "Disallow user registration", "disallow-user-registration": "Disallow user registration",
"disallow-password-auth": "Disallow password auth", "disallow-password-auth": "Disallow password auth",
"disallow-change-username": "Disallow Change Username", "disallow-change-username": "Disallow changing username",
"disallow-change-nickname": "Disallow Change Nickname", "disallow-change-nickname": "Disallow changing nickname",
"week-start-day": "Week start day", "week-start-day": "Week start day",
"saturday": "Saturday", "saturday": "Saturday",
"sunday": "Sunday", "sunday": "Sunday",
@ -391,4 +391,4 @@
"blogs": "Blogs", "blogs": "Blogs",
"documents": "Documents" "documents": "Documents"
} }
} }

@ -1,4 +1,3 @@
import clsx from "clsx";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useMemo } from "react"; import { useMemo } from "react";
import { ExploreSidebar, ExploreSidebarDrawer } from "@/components/ExploreSidebar"; import { ExploreSidebar, ExploreSidebarDrawer } from "@/components/ExploreSidebar";
@ -11,6 +10,7 @@ import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { useMemoFilterStore } from "@/store/v1"; import { useMemoFilterStore } from "@/store/v1";
import { State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
const Explore = () => { const Explore = () => {
const { md } = useResponsiveWidth(); const { md } = useResponsiveWidth();
@ -59,8 +59,8 @@ const Explore = () => {
<ExploreSidebarDrawer /> <ExploreSidebarDrawer />
</MobileHeader> </MobileHeader>
)} )}
<div className={clsx("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}> <div className={cn("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}>
<div className={clsx(md ? "w-[calc(100%-15rem)]" : "w-full")}> <div className={cn(md ? "w-[calc(100%-15rem)]" : "w-full")}>
<MemoFilters /> <MemoFilters />
<div className="flex flex-col justify-start items-start w-full max-w-full"> <div className="flex flex-col justify-start items-start w-full max-w-full">
<PagedMemoList <PagedMemoList

@ -1,4 +1,3 @@
import clsx from "clsx";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useMemo } from "react"; import { useMemo } from "react";
import { HomeSidebar, HomeSidebarDrawer } from "@/components/HomeSidebar"; import { HomeSidebar, HomeSidebarDrawer } from "@/components/HomeSidebar";
@ -12,6 +11,7 @@ import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { useMemoFilterStore } from "@/store/v1"; import { useMemoFilterStore } from "@/store/v1";
import { State } from "@/types/proto/api/v1/common"; import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils";
const Home = () => { const Home = () => {
const { md } = useResponsiveWidth(); const { md } = useResponsiveWidth();
@ -60,8 +60,8 @@ const Home = () => {
<HomeSidebarDrawer /> <HomeSidebarDrawer />
</MobileHeader> </MobileHeader>
)} )}
<div className={clsx("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}> <div className={cn("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}>
<div className={clsx(md ? "w-[calc(100%-15rem)]" : "w-full")}> <div className={cn(md ? "w-[calc(100%-15rem)]" : "w-full")}>
<MemoEditor className="mb-2" cacheKey="home-memo-editor" /> <MemoEditor className="mb-2" cacheKey="home-memo-editor" />
<MemoFilters /> <MemoFilters />
<div className="flex flex-col justify-start items-start w-full max-w-full"> <div className="flex flex-col justify-start items-start w-full max-w-full">

@ -1,5 +1,4 @@
import { Button } from "@usememos/mui"; import { Button } from "@usememos/mui";
import clsx from "clsx";
import { ArrowUpLeftFromCircleIcon, MessageCircleIcon } from "lucide-react"; import { ArrowUpLeftFromCircleIcon, MessageCircleIcon } from "lucide-react";
import { ClientError } from "nice-grpc-web"; import { ClientError } from "nice-grpc-web";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@ -16,6 +15,7 @@ import { memoNamePrefix, useMemoStore, useWorkspaceSettingStore } from "@/store/
import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service"; import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { WorkspaceMemoRelatedSetting, WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceMemoRelatedSetting, WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { memoLink } from "@/utils/memo"; import { memoLink } from "@/utils/memo";
@ -92,8 +92,8 @@ const MemoDetail = () => {
<MemoDetailSidebarDrawer memo={memo} parentPage={locationState?.from} /> <MemoDetailSidebarDrawer memo={memo} parentPage={locationState?.from} />
</MobileHeader> </MobileHeader>
)} )}
<div className={clsx("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}> <div className={cn("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}>
<div className={clsx(md ? "w-[calc(100%-15rem)]" : "w-full")}> <div className={cn(md ? "w-[calc(100%-15rem)]" : "w-full")}>
{parentMemo && ( {parentMemo && (
<div className="w-auto inline-block mb-2"> <div className="w-auto inline-block mb-2">
<Link <Link

@ -0,0 +1 @@
export * from "./utils";

@ -1,6 +1,6 @@
import { type ClassValue, clsx } from "clsx"; import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) { export const cn = (...inputs: ClassValue[]) => {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
} };

Loading…
Cancel
Save