perf: reduce bundle size by 21% with direct icon imports (#3844)

This commit is contained in:
Michel Heusschen 2024-08-28 16:55:28 +02:00 committed by GitHub
parent d11bd30ec6
commit 2dbf92f7f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
63 changed files with 222 additions and 217 deletions

View File

@ -1,7 +1,7 @@
import { Option, Select } from "@mui/joy";
import { SunIcon, MoonIcon, SmileIcon } from "lucide-react";
import { FC } from "react";
import { useTranslate } from "@/utils/i18n";
import Icon from "./Icon";
interface Props {
value: Appearance;
@ -18,11 +18,11 @@ const AppearanceSelect: FC<Props> = (props: Props) => {
const getPrefixIcon = (appearance: Appearance) => {
const className = "w-4 h-auto";
if (appearance === "light") {
return <Icon.Sun className={className} />;
return <SunIcon className={className} />;
} else if (appearance === "dark") {
return <Icon.Moon className={className} />;
return <MoonIcon className={className} />;
} else {
return <Icon.Smile className={className} />;
return <SmileIcon className={className} />;
}
};

View File

@ -1,11 +1,11 @@
import { Button, IconButton, Input } from "@mui/joy";
import { XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { useUserStore } from "@/store/v1";
import { User } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
interface Props extends DialogProps {
user: User;
@ -71,7 +71,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
{t("setting.account-section.change-password")} ({user.nickname})
</p>
<IconButton size="sm" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container">

View File

@ -1,4 +1,5 @@
import { Button, IconButton, Input } from "@mui/joy";
import { XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import useCurrentUser from "@/hooks/useCurrentUser";
@ -6,7 +7,6 @@ import { useCommonContext } from "@/layouts/CommonContextProvider";
import { useUserStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
type Props = DialogProps;
@ -70,7 +70,7 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
<div className="dialog-header-container !w-64">
<p className="title-text">{t("setting.account-section.change-password")}</p>
<IconButton size="sm" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container">

View File

@ -1,4 +1,5 @@
import { Button, IconButton, Input, Radio, RadioGroup } from "@mui/joy";
import { XIcon } from "lucide-react";
import React, { useState } from "react";
import { toast } from "react-hot-toast";
import { userServiceClient } from "@/grpcweb";
@ -6,7 +7,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import useLoading from "@/hooks/useLoading";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
interface Props extends DialogProps {
onConfirm: () => void;
@ -87,7 +87,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
<div className="dialog-header-container">
<p className="title-text">Create access token</p>
<IconButton size="sm" onClick={() => destroy()}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container !w-80">

View File

@ -1,4 +1,5 @@
import { Button, Divider, IconButton, Input, Option, Select, Typography } from "@mui/joy";
import { XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { identityProviderServiceClient } from "@/grpcweb";
@ -6,7 +7,6 @@ import { absolutifyLink } from "@/helpers/utils";
import { FieldMapping, IdentityProvider, IdentityProvider_Type, OAuth2Config } from "@/types/proto/api/v1/idp_service";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
const templateList: IdentityProvider[] = [
{
@ -245,7 +245,7 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
<div className="dialog-header-container">
<p>{t(isCreating ? "setting.sso-section.create-sso" : "setting.sso-section.update-sso")}</p>
<IconButton size="sm" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container min-w-[19rem]">

View File

@ -1,11 +1,11 @@
import { Button, IconButton, Input } from "@mui/joy";
import { XIcon } from "lucide-react";
import React, { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { webhookServiceClient } from "@/grpcweb";
import useLoading from "@/hooks/useLoading";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
interface Props extends DialogProps {
webhookId?: number;
@ -97,7 +97,7 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
<div className="dialog-header-container">
<p className="title-text">{isCreating ? "Create webhook" : "Edit webhook"}</p>
<IconButton size="sm" onClick={() => destroy()}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container !w-80">

View File

@ -1,9 +1,9 @@
import Icon from "./Icon";
import { BirdIcon } from "lucide-react";
const Empty = () => {
return (
<div className="mx-auto">
<Icon.Bird strokeWidth={1} className="w-24 h-auto text-gray-500 dark:text-gray-400" />
<BirdIcon strokeWidth={1} className="w-24 h-auto text-gray-500 dark:text-gray-400" />
</div>
);
};

View File

@ -1,7 +1,7 @@
import { Drawer, IconButton } from "@mui/joy";
import { SearchIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import Icon from "../Icon";
import ExploreSidebar from "./ExploreSidebar";
const ExploreSidebarDrawer = () => {
@ -23,7 +23,7 @@ const ExploreSidebarDrawer = () => {
return (
<>
<IconButton onClick={toggleDrawer(true)}>
<Icon.Search className="w-5 h-auto dark:text-gray-400" />
<SearchIcon className="w-5 h-auto dark:text-gray-400" />
</IconButton>
<Drawer anchor="right" size="sm" open={open} onClose={toggleDrawer(false)}>
<div className="w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900">

View File

@ -1,7 +1,7 @@
import { Drawer, IconButton } from "@mui/joy";
import { SearchIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import Icon from "../Icon";
import HomeSidebar from "./HomeSidebar";
const HomeSidebarDrawer = () => {
@ -23,7 +23,7 @@ const HomeSidebarDrawer = () => {
return (
<>
<IconButton onClick={toggleDrawer(true)}>
<Icon.Search className="w-5 h-auto dark:text-gray-400" />
<SearchIcon className="w-5 h-auto dark:text-gray-400" />
</IconButton>
<Drawer anchor="right" size="sm" open={open} onClose={toggleDrawer(false)}>
<div className="w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900">

View File

@ -1,5 +1,6 @@
import { Dropdown, Menu, MenuButton, MenuItem, Switch } from "@mui/joy";
import clsx from "clsx";
import { Edit3Icon, HashIcon, MoreVerticalIcon, TagsIcon, TrashIcon } from "lucide-react";
import toast from "react-hot-toast";
import { useLocation } from "react-router-dom";
import useDebounce from "react-use/lib/useDebounce";
@ -8,7 +9,6 @@ import { memoServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoFilterStore, useMemoList, useTagStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import Icon from "../Icon";
import showRenameTagDialog from "../RenameTagDialog";
import TagTree from "../TagTree";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/Popover";
@ -66,7 +66,7 @@ const TagsSection = (props: Props) => {
{tagAmounts.length > 0 && (
<Popover>
<PopoverTrigger>
<Icon.MoreVertical className="w-4 h-auto shrink-0 opacity-60" />
<MoreVerticalIcon className="w-4 h-auto shrink-0 opacity-60" />
</PopoverTrigger>
<PopoverContent align="end" alignOffset={-12}>
<div className="w-auto flex flex-row justify-between items-center gap-2">
@ -90,17 +90,17 @@ const TagsSection = (props: Props) => {
<Dropdown>
<MenuButton slots={{ root: "div" }}>
<div className="shrink-0 group">
<Icon.Hash className="group-hover:hidden w-4 h-auto shrink-0 opacity-40" />
<Icon.MoreVertical className="hidden group-hover:block w-4 h-auto shrink-0 opacity-60" />
<HashIcon className="group-hover:hidden w-4 h-auto shrink-0 opacity-40" />
<MoreVerticalIcon className="hidden group-hover:block w-4 h-auto shrink-0 opacity-60" />
</div>
</MenuButton>
<Menu size="sm" placement="bottom-start">
<MenuItem onClick={() => showRenameTagDialog({ tag: tag })}>
<Icon.Edit3 className="w-4 h-auto" />
<Edit3Icon className="w-4 h-auto" />
{t("common.rename")}
</MenuItem>
<MenuItem color="danger" onClick={() => handleDeleteTag(tag)}>
<Icon.Trash className="w-4 h-auto" />
<TrashIcon className="w-4 h-auto" />
{t("common.delete")}
</MenuItem>
</Menu>
@ -119,7 +119,7 @@ const TagsSection = (props: Props) => {
) : (
!props.readonly && (
<div className="p-2 border border-dashed dark:border-zinc-800 rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500">
<Icon.Tags />
<TagsIcon />
<p className="mt-0.5 text-sm leading-snug italic">{t("tag.create-tags-guide")}</p>
</div>
)

View File

@ -1,3 +0,0 @@
import * as Icon from "lucide-react";
export default Icon;

View File

@ -1,5 +1,6 @@
import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { InboxIcon, MessageCircleIcon } from "lucide-react";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { activityServiceClient } from "@/grpcweb";
@ -9,7 +10,6 @@ import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import { Memo } from "@/types/proto/api/v1/memo_service";
import { User } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import Icon from "../Icon";
interface Props {
inbox: Inbox;
@ -81,7 +81,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
)}
>
<Tooltip title={"Comment"} placement="bottom">
<Icon.MessageCircle className="w-4 sm:w-5 h-auto" />
<MessageCircleIcon className="w-4 sm:w-5 h-auto" />
</Tooltip>
</div>
<div
@ -95,10 +95,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
<div>
{inbox.status === Inbox_Status.UNREAD && (
<Tooltip title={t("common.archive")} placement="top">
<Icon.Inbox
className="w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600"
onClick={() => handleArchiveMessage()}
/>
<InboxIcon className="w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600" onClick={() => handleArchiveMessage()} />
</Tooltip>
)}
</div>

View File

@ -1,5 +1,6 @@
import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { ArrowUpIcon, InboxIcon } from "lucide-react";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { activityServiceClient } from "@/grpcweb";
@ -7,7 +8,6 @@ import { activityNamePrefix, useInboxStore } from "@/store/v1";
import { Activity } from "@/types/proto/api/v1/activity_service";
import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import { useTranslate } from "@/utils/i18n";
import Icon from "../Icon";
interface Props {
inbox: Inbox;
@ -66,7 +66,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
)}
>
<Tooltip title={"Update"} placement="bottom">
<Icon.ArrowUp className="w-4 sm:w-5 h-auto" />
<ArrowUpIcon className="w-4 sm:w-5 h-auto" />
</Tooltip>
</div>
<div
@ -80,10 +80,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
<div>
{inbox.status === Inbox_Status.UNREAD && (
<Tooltip title={t("common.archive")} placement="top">
<Icon.Inbox
className="w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600"
onClick={() => handleArchiveMessage()}
/>
<InboxIcon className="w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600" onClick={() => handleArchiveMessage()} />
</Tooltip>
)}
</div>

View File

@ -1,6 +1,6 @@
import { Tooltip } from "@mui/joy";
import { ExternalLinkIcon } from "lucide-react";
import { useTranslate } from "@/utils/i18n";
import Icon from "./Icon";
interface Props {
className?: string;
@ -15,7 +15,7 @@ const LearnMore: React.FC<Props> = (props: Props) => {
return (
<Tooltip title={title ?? t("common.learn-more")} placement="top">
<a className={`text-gray-500 dark:text-gray-400 hover:text-blue-600 ${className}`} href={url} target="_blank">
<Icon.ExternalLink className="w-4 h-auto" />
<ExternalLinkIcon className="w-4 h-auto" />
</a>
</Tooltip>
);

View File

@ -1,7 +1,7 @@
import { Option, Select } from "@mui/joy";
import { GlobeIcon } from "lucide-react";
import { FC } from "react";
import { locales } from "@/i18n";
import Icon from "./Icon";
interface Props {
value: Locale;
@ -19,7 +19,7 @@ const LocaleSelect: FC<Props> = (props: Props) => {
return (
<Select
className={`!min-w-[10rem] w-auto whitespace-nowrap ${className ?? ""}`}
startDecorator={<Icon.Globe className="w-4 h-auto" />}
startDecorator={<GlobeIcon className="w-4 h-auto" />}
value={value}
onChange={(_, value) => handleSelectChange(value as Locale)}
>

View File

@ -1,9 +1,18 @@
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import clsx from "clsx";
import copy from "copy-to-clipboard";
import {
ArchiveIcon,
ArchiveRestoreIcon,
BookmarkMinusIcon,
BookmarkPlusIcon,
CopyIcon,
Edit3Icon,
MoreVerticalIcon,
TrashIcon,
} from "lucide-react";
import toast from "react-hot-toast";
import { useLocation } from "react-router-dom";
import Icon from "@/components/Icon";
import useNavigateTo from "@/hooks/useNavigateTo";
import { useMemoStore } from "@/store/v1";
import { RowStatus } from "@/types/proto/api/v1/common";
@ -108,34 +117,34 @@ const MemoActionMenu = (props: Props) => {
<Dropdown>
<MenuButton slots={{ root: "div" }}>
<span className={clsx("flex justify-center items-center rounded-full hover:opacity-70", props.className)}>
<Icon.MoreVertical 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>
</MenuButton>
<Menu className="text-sm" size="sm" placement="bottom-end">
{!hiddenActions?.includes("pin") && (
<MenuItem onClick={handleTogglePinMemoBtnClick}>
{memo.pinned ? <Icon.BookmarkMinus className="w-4 h-auto" /> : <Icon.BookmarkPlus className="w-4 h-auto" />}
{memo.pinned ? <BookmarkMinusIcon className="w-4 h-auto" /> : <BookmarkPlusIcon className="w-4 h-auto" />}
{memo.pinned ? t("common.unpin") : t("common.pin")}
</MenuItem>
)}
{!hiddenActions?.includes("edit") && props.onEdit && (
<MenuItem onClick={handleEditMemoClick}>
<Icon.Edit3 className="w-4 h-auto" />
<Edit3Icon className="w-4 h-auto" />
{t("common.edit")}
</MenuItem>
)}
{!hiddenActions?.includes("share") && (
<MenuItem onClick={handleCopyLink}>
<Icon.Copy className="w-4 h-auto" />
<CopyIcon className="w-4 h-auto" />
{t("memo.copy-link")}
</MenuItem>
)}
<MenuItem color="warning" onClick={handleToggleMemoStatusClick}>
{memo.rowStatus === RowStatus.ARCHIVED ? <Icon.ArchiveRestore className="w-4 h-auto" /> : <Icon.Archive className="w-4 h-auto" />}
{memo.rowStatus === RowStatus.ARCHIVED ? <ArchiveRestoreIcon className="w-4 h-auto" /> : <ArchiveIcon className="w-4 h-auto" />}
{memo.rowStatus === RowStatus.ARCHIVED ? t("common.restore") : t("common.archive")}
</MenuItem>
<MenuItem color="danger" onClick={handleDeleteMemoClick}>
<Icon.Trash className="w-4 h-auto" />
<TrashIcon className="w-4 h-auto" />
{t("common.delete")}
</MenuItem>
</Menu>

View File

@ -2,9 +2,9 @@ import clsx from "clsx";
import copy from "copy-to-clipboard";
import DOMPurify from "dompurify";
import hljs from "highlight.js";
import { CopyIcon } from "lucide-react";
import { useCallback, useMemo } from "react";
import toast from "react-hot-toast";
import Icon from "../Icon";
import MermaidBlock from "./MermaidBlock";
import { BaseProps } from "./types";
@ -57,7 +57,7 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
<div className="w-full my-1 bg-amber-100 border-l-4 border-amber-400 rounded hover:shadow dark:bg-zinc-600 dark:border-zinc-400 relative">
<div className="w-full px-2 py-1 flex flex-row justify-between items-center text-amber-500 dark:text-zinc-400">
<span className="text-sm font-mono">{formatedLanguage}</span>
<Icon.Copy className="w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} />
<CopyIcon className="w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} />
</div>
<div className="overflow-auto">

View File

@ -1,9 +1,9 @@
import clsx from "clsx";
import copy from "copy-to-clipboard";
import { ArrowUpRightIcon } from "lucide-react";
import { useContext, useEffect } from "react";
import toast from "react-hot-toast";
import { Link } from "react-router-dom";
import Icon from "@/components/Icon";
import MemoResourceListView from "@/components/MemoResourceListView";
import useLoading from "@/hooks/useLoading";
import { useMemoStore } from "@/store/v1";
@ -76,7 +76,7 @@ const EmbeddedMemo = ({ resourceId: uid, params: paramsStr }: Props) => {
{memo.uid.slice(0, 8)}
</span>
<Link className="opacity-60 hover:opacity-80" to={`/m/${memo.uid}`} unstable_viewTransition>
<Icon.ArrowUpRight className="w-5 h-auto" />
<ArrowUpRightIcon className="w-5 h-auto" />
</Link>
</div>
</div>

View File

@ -1,8 +1,8 @@
import clsx from "clsx";
import { isEqual } from "lodash-es";
import { CheckCircleIcon, Code2Icon, HashIcon, LinkIcon } from "lucide-react";
import { Memo, MemoProperty } from "@/types/proto/api/v1/memo_service";
import { useTranslate } from "@/utils/i18n";
import Icon from "../Icon";
interface Props {
memo: Memo;
@ -45,7 +45,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
{property.hasLink && (
<div className="w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center">
<div className="w-auto flex justify-start items-center mr-1">
<Icon.Link className="w-4 h-auto mr-1" />
<LinkIcon className="w-4 h-auto mr-1" />
<span className="block text-sm">{t("memo.links")}</span>
</div>
</div>
@ -53,7 +53,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
{property.hasTaskList && (
<div className="w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center">
<div className="w-auto flex justify-start items-center mr-1">
<Icon.CheckCircle className="w-4 h-auto mr-1" />
<CheckCircleIcon className="w-4 h-auto mr-1" />
<span className="block text-sm">{t("memo.to-do")}</span>
</div>
</div>
@ -61,7 +61,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
{property.hasCode && (
<div className="w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center">
<div className="w-auto flex justify-start items-center mr-1">
<Icon.Code2 className="w-4 h-auto mr-1" />
<Code2Icon className="w-4 h-auto mr-1" />
<span className="block text-sm">{t("memo.code")}</span>
</div>
</div>
@ -81,7 +81,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
key={tag}
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"
>
<Icon.Hash 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)]")}>
<span className="truncate dark:opacity-80">{tag}</span>
</div>

View File

@ -1,8 +1,8 @@
import { Drawer, IconButton } from "@mui/joy";
import { GanttChartIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import { Memo } from "@/types/proto/api/v1/memo_service";
import Icon from "../Icon";
import MemoDetailSidebar from "./MemoDetailSidebar";
interface Props {
@ -27,7 +27,7 @@ const MemoDetailSidebarDrawer = ({ memo }: Props) => {
return (
<>
<IconButton onClick={toggleDrawer(true)}>
<Icon.GanttChart className="w-5 h-auto dark:text-gray-400" />
<GanttChartIcon className="w-5 h-auto dark:text-gray-400" />
</IconButton>
<Drawer anchor="right" size="sm" open={open} onClose={toggleDrawer(false)}>
<div className="w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900">

View File

@ -1,7 +1,7 @@
import { Option, Select } from "@mui/joy";
import clsx from "clsx";
import { Settings2Icon } from "lucide-react";
import { useMemoFilterStore } from "@/store/v1";
import Icon from "./Icon";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
interface Props {
@ -17,7 +17,7 @@ const MemoDisplaySettingMenu = ({ className }: Props) => {
<PopoverTrigger
className={clsx(className, isApplying ? "text-teal-600 bg-teal-50 dark:text-teal-500 dark:bg-teal-900 rounded-sm" : "opacity-40")}
>
<Icon.Settings2 className="w-4 h-auto shrink-0" />
<Settings2Icon className="w-4 h-auto shrink-0" />
</PopoverTrigger>
<PopoverContent align="end" alignOffset={-12} sideOffset={14}>
<div className="flex flex-col gap-2">

View File

@ -1,9 +1,9 @@
import { Autocomplete, AutocompleteOption, Button, Checkbox, Chip, IconButton } from "@mui/joy";
import { uniqBy } from "lodash-es";
import { LinkIcon } from "lucide-react";
import React, { useContext, useState } from "react";
import { toast } from "react-hot-toast";
import useDebounce from "react-use/lib/useDebounce";
import Icon from "@/components/Icon";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/Popover";
import { memoServiceClient } from "@/grpcweb";
import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
@ -127,7 +127,7 @@ const AddMemoRelationPopover = (props: Props) => {
<Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
<PopoverTrigger>
<IconButton size="sm" component="div">
<Icon.Link className="w-5 h-5 mx-auto" />
<LinkIcon className="w-5 h-5 mx-auto" />
</IconButton>
</PopoverTrigger>
<PopoverContent align="center">

View File

@ -1,6 +1,6 @@
import { Dropdown, IconButton, Menu, MenuButton, MenuItem } from "@mui/joy";
import { Link } from "@mui/joy";
import Icon from "@/components/Icon";
import { CheckSquareIcon, Code2Icon, SquareSlashIcon } from "lucide-react";
import { EditorRefActions } from "../Editor";
interface Props {
@ -67,15 +67,15 @@ const MarkdownMenu = (props: Props) => {
},
}}
>
<Icon.SquareSlash className="w-5 h-5 mx-auto" />
<SquareSlashIcon className="w-5 h-5 mx-auto" />
</MenuButton>
<Menu className="text-sm" size="sm" placement="bottom-start">
<MenuItem onClick={handleCodeBlockClick}>
<Icon.Code2 className="w-4 h-auto" />
<Code2Icon className="w-4 h-auto" />
<span>Code block</span>
</MenuItem>
<MenuItem onClick={handleCheckboxClick}>
<Icon.CheckSquare className="w-4 h-auto" />
<CheckSquareIcon className="w-4 h-auto" />
<span>Checkbox</span>
</MenuItem>
<div className="-mt-0.5 pl-2">

View File

@ -1,7 +1,7 @@
import { Dropdown, IconButton, Menu, MenuButton } from "@mui/joy";
import { HashIcon } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import useClickAway from "react-use/lib/useClickAway";
import Icon from "@/components/Icon";
import OverflowTip from "@/components/kit/OverflowTip";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useTagStore } from "@/store/v1";
@ -58,7 +58,7 @@ const TagSelector = (props: Props) => {
},
}}
>
<Icon.Hash className="w-5 h-5 mx-auto" />
<HashIcon className="w-5 h-5 mx-auto" />
</MenuButton>
<Menu className="relative text-sm" component="div" size="sm" placement="bottom-start">
<div ref={containerRef}>

View File

@ -1,7 +1,7 @@
import { IconButton } from "@mui/joy";
import { PaperclipIcon } from "lucide-react";
import { useContext, useRef, useState } from "react";
import toast from "react-hot-toast";
import Icon from "@/components/Icon";
import { useResourceStore } from "@/store/v1";
import { Resource } from "@/types/proto/api/v1/resource_service";
import { MemoEditorContext } from "../types";
@ -67,7 +67,7 @@ const UploadResourceButton = () => {
return (
<IconButton size="sm" disabled={state.uploadingFlag}>
<Icon.Paperclip className="w-5 h-5 mx-auto" />
<PaperclipIcon className="w-5 h-5 mx-auto" />
<input
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
ref={fileInputRef}

View File

@ -1,8 +1,8 @@
import { LinkIcon, XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useMemoStore } from "@/store/v1";
import { MemoRelation, MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Memo } from "@/types/proto/api/v1/memo_service";
import Icon from "../Icon";
interface Props {
relationList: MemoRelation[];
@ -41,9 +41,9 @@ const RelationListView = (props: Props) => {
className="w-auto max-w-xs overflow-hidden flex flex-row justify-start items-center bg-zinc-100 dark:bg-zinc-900 hover:opacity-80 rounded-md text-sm p-1 px-2 text-gray-500 dark:text-gray-400 cursor-pointer hover:line-through"
onClick={() => handleDeleteRelation(memo)}
>
<Icon.Link className="w-4 h-auto shrink-0 opacity-80" />
<LinkIcon className="w-4 h-auto shrink-0 opacity-80" />
<span className="mx-1 max-w-full text-ellipsis whitespace-nowrap overflow-hidden">{memo.snippet}</span>
<Icon.X className="w-4 h-auto cursor-pointer shrink-0 opacity-60 hover:opacity-100" />
<XIcon className="w-4 h-auto cursor-pointer shrink-0 opacity-60 hover:opacity-100" />
</div>
);
})}

View File

@ -1,7 +1,7 @@
import { DndContext, closestCenter, MouseSensor, TouchSensor, useSensor, useSensors, DragEndEvent } from "@dnd-kit/core";
import { arrayMove, SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { XIcon } from "lucide-react";
import { Resource } from "@/types/proto/api/v1/resource_service";
import Icon from "../Icon";
import ResourceIcon from "../ResourceIcon";
import SortableItem from "./SortableItem";
@ -45,7 +45,7 @@ const ResourceListView = (props: Props) => {
<span className="text-sm max-w-[8rem] truncate">{resource.filename}</span>
</SortableItem>
<button className="shrink-0" onClick={() => handleDeleteResource(resource.name)}>
<Icon.X className="w-4 h-auto cursor-pointer opacity-60 hover:opacity-100" />
<XIcon className="w-4 h-auto cursor-pointer opacity-60 hover:opacity-100" />
</button>
</div>
);

View File

@ -1,5 +1,6 @@
import { Select, Option, Button, Divider } from "@mui/joy";
import { isEqual } from "lodash-es";
import { SendIcon } from "lucide-react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
@ -18,7 +19,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
import { convertVisibilityFromString, convertVisibilityToString } from "@/utils/memo";
import Icon from "../Icon";
import VisibilityIcon from "../VisibilityIcon";
import AddMemoRelationPopover from "./ActionButton/AddMemoRelationPopover";
import MarkdownMenu from "./ActionButton/MarkdownMenu";
@ -473,7 +473,7 @@ const MemoEditor = (props: Props) => {
className="!font-normal"
disabled={!allowSave}
loading={state.isRequesting}
endDecorator={<Icon.Send className="w-4 h-auto" />}
endDecorator={<SendIcon className="w-4 h-auto" />}
onClick={handleSaveBtnClick}
>
{t("editor.save")}

View File

@ -1,6 +1,6 @@
import { isEqual } from "lodash-es";
import { CalendarIcon, CheckCircleIcon, CodeIcon, EyeIcon, FilterIcon, LinkIcon, SearchIcon, TagIcon, XIcon } from "lucide-react";
import { FilterFactor, getMemoFilterKey, MemoFilter, useMemoFilterStore } from "@/store/v1";
import Icon from "./Icon";
const MemoFilters = () => {
const memoFilterStore = useMemoFilterStore();
@ -23,7 +23,7 @@ const MemoFilters = () => {
return (
<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">
<Icon.Filter className="w-4 h-auto opacity-60 inline" />
<FilterIcon className="w-4 h-auto opacity-60 inline" />
Filters
</span>
<div className="flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6">
@ -36,7 +36,7 @@ const MemoFilters = () => {
<FactorIcon className="w-4 h-auto text-gray-500 dark:text-gray-400 opacity-60" factor={filter.factor} />
<span className="text-gray-500 dark:text-gray-400 text-sm max-w-32 truncate">{getFilterDisplayText(filter)}</span>
<button className="text-gray-500 dark:text-gray-300 opacity-60 hover:opacity-100">
<Icon.X className="w-4 h-auto" />
<XIcon className="w-4 h-auto" />
</button>
</div>
))}
@ -47,13 +47,13 @@ const MemoFilters = () => {
const FactorIcon = ({ factor, className }: { factor: FilterFactor; className?: string }) => {
const iconMap = {
tagSearch: <Icon.Tag className={className} />,
visibility: <Icon.Eye className={className} />,
contentSearch: <Icon.Search className={className} />,
displayTime: <Icon.Calendar className={className} />,
"property.hasLink": <Icon.Link className={className} />,
"property.hasTaskList": <Icon.CheckCircle className={className} />,
"property.hasCode": <Icon.Code className={className} />,
tagSearch: <TagIcon className={className} />,
visibility: <EyeIcon className={className} />,
contentSearch: <SearchIcon className={className} />,
displayTime: <CalendarIcon className={className} />,
"property.hasLink": <LinkIcon className={className} />,
"property.hasTaskList": <CheckCircleIcon className={className} />,
"property.hasCode": <CodeIcon className={className} />,
};
return iconMap[factor as keyof typeof iconMap] || <></>;
};

View File

@ -1,11 +1,11 @@
import clsx from "clsx";
import { DotIcon, LinkIcon, MilestoneIcon } from "lucide-react";
import { memo, useState } from "react";
import { Link } from "react-router-dom";
import useAsyncEffect from "@/hooks/useAsyncEffect";
import { useMemoStore } from "@/store/v1";
import { MemoRelation } from "@/types/proto/api/v1/memo_relation_service";
import { Memo } from "@/types/proto/api/v1/memo_service";
import Icon from "./Icon";
interface Props {
memo: Memo;
@ -54,7 +54,7 @@ const MemoRelationListView = (props: Props) => {
)}
onClick={() => setSelectedTab("referencing")}
>
<Icon.Link className="w-3 h-auto shrink-0 opacity-70" />
<LinkIcon className="w-3 h-auto shrink-0 opacity-70" />
<span>Referencing</span>
<span className="opacity-80">({referencingMemoList.length})</span>
</button>
@ -67,7 +67,7 @@ const MemoRelationListView = (props: Props) => {
)}
onClick={() => setSelectedTab("referenced")}
>
<Icon.Milestone className="w-3 h-auto shrink-0 opacity-70" />
<MilestoneIcon className="w-3 h-auto shrink-0 opacity-70" />
<span>Referenced by</span>
<span className="opacity-80">({referencedMemoList.length})</span>
</button>
@ -83,7 +83,7 @@ const MemoRelationListView = (props: Props) => {
to={`/m/${memo.uid}`}
unstable_viewTransition
>
<Icon.Dot className="shrink-0 w-4 h-auto opacity-40" />
<DotIcon className="shrink-0 w-4 h-auto opacity-40" />
<span className="truncate">{memo.snippet}</span>
</Link>
);
@ -100,7 +100,7 @@ const MemoRelationListView = (props: Props) => {
to={`/m/${memo.uid}`}
unstable_viewTransition
>
<Icon.Dot className="shrink-0 w-4 h-auto opacity-40" />
<DotIcon className="shrink-0 w-4 h-auto opacity-40" />
<span className="truncate">{memo.snippet}</span>
</Link>
);

View File

@ -1,5 +1,6 @@
import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { BookmarkIcon, MessageCircleMoreIcon } from "lucide-react";
import { memo, useCallback, useEffect, useRef, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import useCurrentUser from "@/hooks/useCurrentUser";
@ -11,7 +12,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
import { convertVisibilityToString } from "@/utils/memo";
import Icon from "./Icon";
import MemoActionMenu from "./MemoActionMenu";
import MemoContent from "./MemoContent";
import MemoEditor from "./MemoEditor";
@ -169,13 +169,13 @@ const MemoView: React.FC<Props> = (props: Props) => {
to={`/m/${memo.uid}#comments`}
unstable_viewTransition
>
<Icon.MessageCircleMore className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
<MessageCircleMoreIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
{commentAmount > 0 && <span className="text-xs text-gray-500 dark:text-gray-400">{commentAmount}</span>}
</Link>
)}
{props.showPinned && memo.pinned && (
<Tooltip title={t("common.pinned")} placement="top">
<Icon.Bookmark className="w-4 h-auto text-amber-500" />
<BookmarkIcon className="w-4 h-auto text-amber-500" />
</Tooltip>
)}
{!readonly && (

View File

@ -1,5 +1,6 @@
import { Tooltip } from "@mui/joy";
import clsx from "clsx";
import { ArchiveIcon, BellIcon, Globe2Icon, HomeIcon, LogInIcon, PaperclipIcon, SettingsIcon, SmileIcon, User2Icon } from "lucide-react";
import { useEffect } from "react";
import { NavLink } from "react-router-dom";
import useCurrentUser from "@/hooks/useCurrentUser";
@ -7,7 +8,6 @@ import { Routes } from "@/router";
import { useInboxStore } from "@/store/v1";
import { Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import { useTranslate } from "@/utils/i18n";
import Icon from "./Icon";
import UserBanner from "./UserBanner";
interface NavLinkItem {
@ -52,25 +52,25 @@ const Navigation = (props: Props) => {
id: "header-home",
path: Routes.ROOT,
title: t("common.home"),
icon: <Icon.Home className="w-6 h-auto opacity-70 shrink-0" />,
icon: <HomeIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const resourcesNavLink: NavLinkItem = {
id: "header-resources",
path: Routes.RESOURCES,
title: t("common.resources"),
icon: <Icon.Paperclip className="w-6 h-auto opacity-70 shrink-0" />,
icon: <PaperclipIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const exploreNavLink: NavLinkItem = {
id: "header-explore",
path: Routes.EXPLORE,
title: t("common.explore"),
icon: <Icon.Globe2 className="w-6 h-auto opacity-70 shrink-0" />,
icon: <Globe2Icon className="w-6 h-auto opacity-70 shrink-0" />,
};
const profileNavLink: NavLinkItem = {
id: "header-profile",
path: user ? `/u/${encodeURIComponent(user.username)}` : "",
title: t("common.profile"),
icon: <Icon.User2 className="w-6 h-auto opacity-70 shrink-0" />,
icon: <User2Icon className="w-6 h-auto opacity-70 shrink-0" />,
};
const inboxNavLink: NavLinkItem = {
id: "header-inbox",
@ -79,7 +79,7 @@ const Navigation = (props: Props) => {
icon: (
<>
<div className="relative">
<Icon.Bell className="w-6 h-auto opacity-70 shrink-0" />
<BellIcon className="w-6 h-auto opacity-70 shrink-0" />
{hasUnreadInbox && <div className="absolute top-0 left-5 w-2 h-2 rounded-full bg-blue-500"></div>}
</div>
</>
@ -89,25 +89,25 @@ const Navigation = (props: Props) => {
id: "header-archived",
path: Routes.ARCHIVED,
title: t("common.archived"),
icon: <Icon.Archive className="w-6 h-auto opacity-70 shrink-0" />,
icon: <ArchiveIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const settingNavLink: NavLinkItem = {
id: "header-setting",
path: Routes.SETTING,
title: t("common.settings"),
icon: <Icon.Settings className="w-6 h-auto opacity-70 shrink-0" />,
icon: <SettingsIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const signInNavLink: NavLinkItem = {
id: "header-auth",
path: Routes.AUTH,
title: t("common.sign-in"),
icon: <Icon.LogIn className="w-6 h-auto opacity-70 shrink-0" />,
icon: <LogInIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const aboutNavLink: NavLinkItem = {
id: "header-about",
path: Routes.ABOUT,
title: t("common.about"),
icon: <Icon.Smile className="w-6 h-auto opacity-70 shrink-0" />,
icon: <SmileIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const navLinks: NavLinkItem[] = user

View File

@ -1,7 +1,7 @@
import { Drawer, IconButton } from "@mui/joy";
import { MenuIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import Icon from "./Icon";
import Navigation from "./Navigation";
const NavigationDrawer = () => {
@ -23,7 +23,7 @@ const NavigationDrawer = () => {
return (
<>
<IconButton onClick={toggleDrawer(true)}>
<Icon.Menu className="w-5 h-auto dark:text-gray-400" />
<MenuIcon className="w-5 h-auto dark:text-gray-400" />
</IconButton>
<Drawer anchor="left" size="sm" open={open} onClose={toggleDrawer(false)}>
<div className="w-full h-full overflow-auto px-4 bg-zinc-100 dark:bg-zinc-900">

View File

@ -1,6 +1,6 @@
import { XIcon } from "lucide-react";
import React, { useState } from "react";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
import "@/less/preview-image-dialog.less";
const MIN_SCALE = 0.5;
@ -116,7 +116,7 @@ const PreviewImageDialog: React.FC<Props> = ({ destroy, imgUrls, initialIndex }:
<>
<div className="btns-container">
<button className="btn" onClick={handleCloseBtnClick}>
<Icon.X className="icon-img" />
<XIcon className="icon-img" />
</button>
</div>
<div className="img-container" onClick={handleImgContainerClick}>

View File

@ -1,8 +1,8 @@
import { Dropdown, Menu, MenuButton } from "@mui/joy";
import clsx from "clsx";
import { SmilePlusIcon } from "lucide-react";
import { useRef, useState } from "react";
import useClickAway from "react-use/lib/useClickAway";
import Icon from "@/components/Icon";
import { memoServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoStore } from "@/store/v1";
@ -76,7 +76,7 @@ const ReactionSelector = (props: Props) => {
<span
className={clsx("h-7 w-7 flex justify-center items-center rounded-full border dark:border-zinc-700 hover:opacity-70", className)}
>
<Icon.SmilePlus 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>
</MenuButton>
<Menu className="relative text-sm" component="div" size="sm" placement="bottom-start">

View File

@ -1,4 +1,5 @@
import { Button, IconButton, Input, List, ListItem } from "@mui/joy";
import { XIcon } from "lucide-react";
import React, { useState } from "react";
import { toast } from "react-hot-toast";
import { memoServiceClient } from "@/grpcweb";
@ -7,7 +8,6 @@ import useLoading from "@/hooks/useLoading";
import { useTagStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
interface Props extends DialogProps {
tag: string;
@ -55,7 +55,7 @@ const RenameTagDialog: React.FC<Props> = (props: Props) => {
<div className="dialog-header-container">
<p className="title-text">{"Rename tag"}</p>
<IconButton size="sm" onClick={() => destroy()}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container max-w-xs">

View File

@ -1,8 +1,18 @@
import clsx from "clsx";
import {
BinaryIcon,
BookIcon,
FileArchiveIcon,
FileAudioIcon,
FileEditIcon,
FileIcon,
FileTextIcon,
FileVideo2Icon,
SheetIcon,
} from "lucide-react";
import React from "react";
import { Resource } from "@/types/proto/api/v1/resource_service";
import { getResourceType, getResourceUrl } from "@/utils/resource";
import Icon from "./Icon";
import showPreviewImageDialog from "./PreviewImageDialog";
import SquareDiv from "./kit/SquareDiv";
@ -40,25 +50,25 @@ const ResourceIcon = (props: Props) => {
const getResourceIcon = () => {
switch (resourceType) {
case "video/*":
return <Icon.FileVideo2 strokeWidth={strokeWidth} className="w-full h-auto" />;
return <FileVideo2Icon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "audio/*":
return <Icon.FileAudio strokeWidth={strokeWidth} className="w-full h-auto" />;
return <FileAudioIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "text/*":
return <Icon.FileText strokeWidth={strokeWidth} className="w-full h-auto" />;
return <FileTextIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "application/epub+zip":
return <Icon.Book strokeWidth={strokeWidth} className="w-full h-auto" />;
return <BookIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "application/pdf":
return <Icon.Book strokeWidth={strokeWidth} className="w-full h-auto" />;
return <BookIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "application/msword":
return <Icon.FileEdit strokeWidth={strokeWidth} className="w-full h-auto" />;
return <FileEditIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "application/msexcel":
return <Icon.SheetIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
return <SheetIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
case "application/zip":
return <Icon.FileArchiveIcon onClick={previewResource} strokeWidth={strokeWidth} className="w-full h-auto" />;
return <FileArchiveIcon onClick={previewResource} strokeWidth={strokeWidth} className="w-full h-auto" />;
case "application/x-java-archive":
return <Icon.BinaryIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
return <BinaryIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
default:
return <Icon.File strokeWidth={strokeWidth} className="w-full h-auto" />;
return <FileIcon strokeWidth={strokeWidth} className="w-full h-auto" />;
}
};

View File

@ -1,7 +1,7 @@
import { SearchIcon } from "lucide-react";
import { useState } from "react";
import { useMemoFilterStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import Icon from "./Icon";
import MemoDisplaySettingMenu from "./MemoDisplaySettingMenu";
const SearchBar = () => {
@ -29,7 +29,7 @@ const SearchBar = () => {
return (
<div className="relative w-full h-auto flex flex-row justify-start items-center">
<Icon.Search className="absolute left-3 w-4 h-auto opacity-40" />
<SearchIcon className="absolute left-3 w-4 h-auto opacity-40" />
<input
className="w-full text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 border dark:border-zinc-800 text-sm leading-7 rounded-lg p-1 pl-8 outline-none"
placeholder={t("memo.search-placeholder")}

View File

@ -1,5 +1,6 @@
import { Button, IconButton } from "@mui/joy";
import copy from "copy-to-clipboard";
import { ClipboardIcon, TrashIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { userServiceClient } from "@/grpcweb";
@ -7,7 +8,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import { UserAccessToken } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import showCreateAccessTokenDialog from "../CreateAccessTokenDialog";
import Icon from "../Icon";
import LearnMore from "../LearnMore";
const listAccessTokens = async (name: string) => {
@ -102,7 +102,7 @@ const AccessTokenSection = () => {
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-900 dark:text-gray-400 flex flex-row justify-start items-center gap-x-1">
<span className="font-mono">{getFormatedAccessToken(userAccessToken.accessToken)}</span>
<IconButton color="neutral" variant="plain" size="sm" onClick={() => copyAccessToken(userAccessToken.accessToken)}>
<Icon.Clipboard className="w-4 h-auto text-gray-400" />
<ClipboardIcon className="w-4 h-auto text-gray-400" />
</IconButton>
</td>
<td className="whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-400">
@ -123,7 +123,7 @@ const AccessTokenSection = () => {
handleDeleteAccessToken(userAccessToken.accessToken);
}}
>
<Icon.Trash className="w-4 h-auto" />
<TrashIcon className="w-4 h-auto" />
</IconButton>
</td>
</tr>

View File

@ -1,5 +1,6 @@
import { Button, Dropdown, Input, Menu, MenuButton, MenuItem, Radio, RadioGroup } from "@mui/joy";
import { sortBy } from "lodash-es";
import { MoreVerticalIcon } from "lucide-react";
import React, { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { userServiceClient } from "@/grpcweb";
@ -9,7 +10,6 @@ import { RowStatus } from "@/types/proto/api/v1/common";
import { User, User_Role } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import showChangeMemberPasswordDialog from "../ChangeMemberPasswordDialog";
import Icon from "../Icon";
interface State {
creatingUser: User;
@ -204,7 +204,7 @@ const MemberSection = () => {
) : (
<Dropdown>
<MenuButton size="sm">
<Icon.MoreVertical className="w-4 h-auto" />
<MoreVerticalIcon className="w-4 h-auto" />
</MenuButton>
<Menu placement="bottom-end" size="sm">
<MenuItem onClick={() => handleChangePasswordClick(user)}>

View File

@ -1,10 +1,10 @@
import { Button, Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import { MoreVerticalIcon, PenLineIcon } from "lucide-react";
import { memoServiceClient } from "@/grpcweb";
import { downloadFileFromUrl } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useTranslate } from "@/utils/i18n";
import showChangePasswordDialog from "../ChangePasswordDialog";
import Icon from "../Icon";
import showUpdateAccountDialog from "../UpdateAccountDialog";
import UserAvatar from "../UserAvatar";
import AccessTokenSection from "./AccessTokenSection";
@ -35,13 +35,13 @@ const MyAccountSection = () => {
</div>
<div className="w-full flex flex-row justify-start items-center mt-2 space-x-2">
<Button variant="outlined" color="neutral" size="sm" onClick={showUpdateAccountDialog}>
<Icon.PenLine className="w-4 h-4 mx-auto mr-1" />
<PenLineIcon className="w-4 h-4 mx-auto mr-1" />
{t("common.edit")}
</Button>
<Dropdown>
<MenuButton slots={{ root: "div" }}>
<Button variant="outlined" color="neutral" size="sm">
<Icon.MoreVertical className="w-4 h-4 mx-auto" />
<MoreVerticalIcon className="w-4 h-4 mx-auto" />
</Button>
</MenuButton>
<Menu className="text-sm" size="sm" placement="bottom">

View File

@ -1,4 +1,5 @@
import { Button, Divider, Dropdown, List, ListItem, Menu, MenuButton, MenuItem } from "@mui/joy";
import { MoreVerticalIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { Link } from "react-router-dom";
@ -6,7 +7,6 @@ import { identityProviderServiceClient } from "@/grpcweb";
import { IdentityProvider } from "@/types/proto/api/v1/idp_service";
import { useTranslate } from "@/utils/i18n";
import showCreateIdentityProviderDialog from "../CreateIdentityProviderDialog";
import Icon from "../Icon";
import LearnMore from "../LearnMore";
const SSOSection = () => {
@ -59,7 +59,7 @@ const SSOSection = () => {
<div className="flex flex-row items-center">
<Dropdown>
<MenuButton size="sm">
<Icon.MoreVertical className="w-4 h-auto" />
<MoreVerticalIcon className="w-4 h-auto" />
</MenuButton>
<Menu placement="bottom-end" size="sm">
<MenuItem onClick={() => showCreateIdentityProviderDialog(identityProvider, fetchIdentityProviderList)}>

View File

@ -1,5 +1,6 @@
import { Button, Divider, Input, List, ListItem, Radio, RadioGroup, Tooltip } from "@mui/joy";
import { isEqual } from "lodash-es";
import { HelpCircleIcon } from "lucide-react";
import { useMemo, useState } from "react";
import { toast } from "react-hot-toast";
import { Link } from "react-router-dom";
@ -11,7 +12,6 @@ import {
} from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
import Icon from "../Icon";
const StorageSection = () => {
const t = useTranslate();
@ -132,7 +132,7 @@ const StorageSection = () => {
<div className="flex flex-row items-center">
<span className="text-gray-700 dark:text-gray-500 mr-1">{t("setting.system-section.max-upload-size")}</span>
<Tooltip title={t("setting.system-section.max-upload-size-hint")} placement="top">
<Icon.HelpCircle className="w-4 h-auto" />
<HelpCircleIcon className="w-4 h-auto" />
</Tooltip>
</div>
<Input

View File

@ -1,4 +1,5 @@
import { Button, IconButton } from "@mui/joy";
import { ExternalLinkIcon, TrashIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { webhookServiceClient } from "@/grpcweb";
@ -6,7 +7,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import { Webhook } from "@/types/proto/api/v1/webhook_service";
import { useTranslate } from "@/utils/i18n";
import showCreateWebhookDialog from "../CreateWebhookDialog";
import Icon from "../Icon";
const listWebhooks = async (userId: number) => {
const { webhooks } = await webhookServiceClient.listWebhooks({
@ -88,7 +88,7 @@ const WebhookSection = () => {
handleDeleteWebhook(webhook);
}}
>
<Icon.Trash className="w-4 h-auto" />
<TrashIcon className="w-4 h-auto" />
</IconButton>
</td>
</tr>
@ -113,7 +113,7 @@ const WebhookSection = () => {
target="_blank"
>
{t("common.learn-more")}
<Icon.ExternalLink className="inline w-4 h-auto ml-1" />
<ExternalLinkIcon className="inline w-4 h-auto ml-1" />
</Link>
</div>
</div>

View File

@ -1,4 +1,5 @@
import { Button, Select, Textarea, Option, Divider } from "@mui/joy";
import { ExternalLinkIcon } from "lucide-react";
import { useState } from "react";
import { toast } from "react-hot-toast";
import { Link } from "react-router-dom";
@ -7,7 +8,6 @@ import { workspaceSettingNamePrefix, useWorkspaceSettingStore } from "@/store/v1
import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
import Icon from "../Icon";
import showUpdateCustomizedProfileDialog from "../UpdateCustomizedProfileDialog";
const WorkspaceSection = () => {
@ -101,7 +101,7 @@ const WorkspaceSection = () => {
target="_blank"
>
{t("common.learn-more")}
<Icon.ExternalLink className="inline w-4 h-auto ml-1" />
<ExternalLinkIcon className="inline w-4 h-auto ml-1" />
</Link>
</div>
<div className="w-full flex flex-row justify-between items-center">

View File

@ -1,7 +1,7 @@
import { ChevronRightIcon, HashIcon } from "lucide-react";
import { useEffect, useState } from "react";
import useToggle from "react-use/lib/useToggle";
import { useMemoFilterStore } from "@/store/v1";
import Icon from "./Icon";
interface Tag {
key: string;
@ -108,7 +108,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
}`}
>
<div className="shrink-0">
<Icon.Hash className="w-4 h-auto shrink-0 mr-1 text-gray-400 dark:text-gray-500" />
<HashIcon className="w-4 h-auto shrink-0 mr-1 text-gray-400 dark:text-gray-500" />
</div>
<span className="truncate cursor-pointer hover:opacity-80" onClick={handleTagClick}>
{tag.key}
@ -120,7 +120,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
className={`flex flex-row justify-center items-center w-6 h-6 shrink-0 transition-all rotate-0 ${showSubTags && "rotate-90"}`}
onClick={handleToggleBtnClick}
>
<Icon.ChevronRight className="w-5 h-5 cursor-pointer text-gray-400 dark:text-gray-500" />
<ChevronRightIcon className="w-5 h-5 cursor-pointer text-gray-400 dark:text-gray-500" />
</span>
) : null}
</div>

View File

@ -1,5 +1,6 @@
import { Button, IconButton, Input, Textarea } from "@mui/joy";
import { isEqual } from "lodash-es";
import { XIcon } from "lucide-react";
import { useState } from "react";
import { toast } from "react-hot-toast";
import { convertFileToBase64 } from "@/helpers/utils";
@ -8,7 +9,6 @@ import { userNamePrefix, useUserStore } from "@/store/v1";
import { User as UserPb } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
import UserAvatar from "./UserAvatar";
type Props = DialogProps;
@ -143,7 +143,7 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
<div className="dialog-header-container !w-64">
<p className="title-text">{t("setting.account-section.update-information")}</p>
<IconButton size="sm" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container space-y-2">
@ -154,7 +154,7 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
<input type="file" accept="image/*" className="absolute invisible w-full h-full inset-0" onChange={handleAvatarChanged} />
</label>
{state.avatarUrl && (
<Icon.X
<XIcon
className="w-4 h-auto ml-1 cursor-pointer opacity-60 hover:opacity-80"
onClick={() =>
setPartialState({

View File

@ -1,5 +1,6 @@
import { Button, IconButton, Input } from "@mui/joy";
import Textarea from "@mui/joy/Textarea/Textarea";
import { XIcon } from "lucide-react";
import { useState } from "react";
import { toast } from "react-hot-toast";
import { workspaceSettingNamePrefix, useWorkspaceSettingStore } from "@/store/v1";
@ -8,7 +9,6 @@ import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
import AppearanceSelect from "./AppearanceSelect";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
import LocaleSelect from "./LocaleSelect";
type Props = DialogProps;
@ -103,7 +103,7 @@ const UpdateCustomizedProfileDialog: React.FC<Props> = ({ destroy }: Props) => {
<div className="dialog-header-container">
<p className="title-text">{t("setting.system-section.customize-server.title")}</p>
<IconButton size="sm" onClick={handleCloseButtonClick}>
<Icon.X className="w-5 h-auto" />
<XIcon className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container min-w-[16rem]">

View File

@ -1,11 +1,11 @@
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import clsx from "clsx";
import { LogOutIcon, SmileIcon } from "lucide-react";
import { authServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import useNavigateTo from "@/hooks/useNavigateTo";
import { Routes } from "@/router";
import { useTranslate } from "@/utils/i18n";
import Icon from "./Icon";
import UserAvatar from "./UserAvatar";
interface Props {
@ -41,11 +41,11 @@ const UserBanner = (props: Props) => {
</MenuButton>
<Menu placement="bottom-start" style={{ zIndex: "9999" }}>
<MenuItem onClick={handleSignOut}>
<Icon.LogOut className="w-4 h-auto opacity-60" />
<LogOutIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.sign-out")}</span>
</MenuItem>
<MenuItem onClick={() => navigateTo(Routes.ABOUT)}>
<Icon.Smile className="w-4 h-auto opacity-60" />
<SmileIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.about")}</span>
</MenuItem>
</Menu>

View File

@ -2,6 +2,7 @@ import { Divider, Tooltip } from "@mui/joy";
import clsx from "clsx";
import dayjs from "dayjs";
import { countBy } from "lodash-es";
import { CalendarDaysIcon, CheckCircleIcon, Code2Icon, LinkIcon, ListTodoIcon, MoreVerticalIcon, RefreshCcwIcon } from "lucide-react";
import { useState } from "react";
import toast from "react-hot-toast";
import { memoServiceClient } from "@/grpcweb";
@ -11,7 +12,6 @@ import i18n from "@/i18n";
import { useMemoFilterStore, useMemoStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import ActivityCalendar from "./ActivityCalendar";
import Icon from "./Icon";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
interface UserMemoStats {
@ -75,7 +75,7 @@ const UserStatisticsView = () => {
<div className="group w-full border mt-2 py-2 px-3 rounded-lg space-y-0.5 text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 dark:border-zinc-800">
<div className="w-full mb-1 flex flex-row justify-between items-center">
<div className="relative text-base font-medium leading-6 flex flex-row items-center dark:text-gray-400">
<Icon.CalendarDays className="w-5 h-auto mr-1 opacity-60" strokeWidth={1.5} />
<CalendarDaysIcon className="w-5 h-auto mr-1 opacity-60" strokeWidth={1.5} />
<span>{dayjs(monthString).toDate().toLocaleString(i18n.language, { year: "numeric", month: "long" })}</span>
<input
className="inset-0 absolute z-1 opacity-0"
@ -88,11 +88,11 @@ const UserStatisticsView = () => {
<div className="invisible group-hover:visible flex justify-end items-center">
<Popover>
<PopoverTrigger>
<Icon.MoreVertical className="w-4 h-auto shrink-0 opacity-60" />
<MoreVerticalIcon className="w-4 h-auto shrink-0 opacity-60" />
</PopoverTrigger>
<PopoverContent align="end" alignOffset={-12}>
<button className="w-auto flex flex-row justify-between items-center gap-2 hover:opacity-80" onClick={rebuildMemoTags}>
<Icon.RefreshCcw className="text-gray-400 w-4 h-auto cursor-pointer opacity-60" />
<RefreshCcwIcon className="text-gray-400 w-4 h-auto cursor-pointer opacity-60" />
<span className="text-sm shrink-0 text-gray-500 dark:text-gray-400">Refresh</span>
</button>
</PopoverContent>
@ -114,7 +114,7 @@ const UserStatisticsView = () => {
onClick={() => memoFilterStore.addFilter({ factor: "property.hasLink", value: "" })}
>
<div className="w-auto flex justify-start items-center mr-1">
<Icon.Link className="w-4 h-auto mr-1" />
<LinkIcon className="w-4 h-auto mr-1" />
<span className="block text-sm">{t("memo.links")}</span>
</div>
<span className="text-sm truncate">{memoStats.link}</span>
@ -124,11 +124,7 @@ const UserStatisticsView = () => {
onClick={() => memoFilterStore.addFilter({ factor: "property.hasTaskList", value: "" })}
>
<div className="w-auto flex justify-start items-center mr-1">
{memoStats.incompleteTasks > 0 ? (
<Icon.ListTodo className="w-4 h-auto mr-1" />
) : (
<Icon.CheckCircle className="w-4 h-auto mr-1" />
)}
{memoStats.incompleteTasks > 0 ? <ListTodoIcon className="w-4 h-auto mr-1" /> : <CheckCircleIcon className="w-4 h-auto mr-1" />}
<span className="block text-sm">{t("memo.to-do")}</span>
</div>
{memoStats.incompleteTasks > 0 ? (
@ -148,7 +144,7 @@ const UserStatisticsView = () => {
onClick={() => memoFilterStore.addFilter({ factor: "property.hasCode", value: "" })}
>
<div className="w-auto flex justify-start items-center mr-1">
<Icon.Code2 className="w-4 h-auto mr-1" />
<Code2Icon className="w-4 h-auto mr-1" />
<span className="block text-sm">{t("memo.code")}</span>
</div>
<span className="text-sm truncate">{memoStats.code}</span>

View File

@ -1,6 +1,6 @@
import clsx from "clsx";
import { Globe2Icon, LockIcon, UsersIcon } from "lucide-react";
import { Visibility } from "@/types/proto/api/v1/memo_service";
import Icon from "./Icon";
interface Props {
visibility: Visibility;
@ -11,11 +11,11 @@ const VisibilityIcon = (props: Props) => {
let VIcon = null;
if (visibility === Visibility.PRIVATE) {
VIcon = Icon.Lock;
VIcon = LockIcon;
} else if (visibility === Visibility.PROTECTED) {
VIcon = Icon.Users;
VIcon = UsersIcon;
} else if (visibility === Visibility.PUBLIC) {
VIcon = Icon.Globe2;
VIcon = Globe2Icon;
}
if (!VIcon) {
return null;

View File

@ -1,9 +1,9 @@
import { Button, IconButton, Tooltip } from "@mui/joy";
import clsx from "clsx";
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import { Suspense, useEffect, useState } from "react";
import { Outlet, useLocation } from "react-router-dom";
import useLocalStorage from "react-use/lib/useLocalStorage";
import Icon from "@/components/Icon";
import Navigation from "@/components/Navigation";
import useCurrentUser from "@/hooks/useCurrentUser";
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
@ -55,13 +55,13 @@ const RootLayout = () => {
onClick={() => setCollapsed(!collapsed)}
>
{!collapsed ? (
<Button variant="plain" color="neutral" startDecorator={<Icon.ChevronLeft className="w-5 h-auto opacity-70" />}>
<Button variant="plain" color="neutral" startDecorator={<ChevronLeftIcon className="w-5 h-auto opacity-70" />}>
{t("common.collapse")}
</Button>
) : (
<Tooltip title={t("common.expand")} placement="right" arrow>
<IconButton>
<Icon.ChevronRight className="w-5 h-auto opacity-70" />
<ChevronRightIcon className="w-5 h-auto opacity-70" />
</IconButton>
</Tooltip>
)}

View File

@ -1,5 +1,5 @@
import { Link } from "@mui/joy";
import Icon from "@/components/Icon";
import { DotIcon } from "lucide-react";
import MobileHeader from "@/components/MobileHeader";
const About = () => {
@ -16,15 +16,15 @@ const About = () => {
<Link underline="always" href="https://www.github.com/usememos/memos" target="_blank">
GitHub Repo
</Link>
<Icon.Dot className="w-4 h-auto opacity-60" />
<DotIcon className="w-4 h-auto opacity-60" />
<Link underline="always" href="https://www.usememos.com/" target="_blank">
Official Website
</Link>
<Icon.Dot className="w-4 h-auto opacity-60" />
<DotIcon className="w-4 h-auto opacity-60" />
<Link underline="always" href="https://www.usememos.com/blog" target="_blank">
Blogs
</Link>
<Icon.Dot className="w-4 h-auto opacity-60" />
<DotIcon className="w-4 h-auto opacity-60" />
<Link underline="always" href="https://www.usememos.com/docs" target="_blank">
Documents
</Link>

View File

@ -1,10 +1,10 @@
import { Button, Tooltip } from "@mui/joy";
import dayjs from "dayjs";
import { ArchiveIcon, ArchiveRestoreIcon, ArrowDownIcon, TrashIcon } from "lucide-react";
import { ClientError } from "nice-grpc-web";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import Empty from "@/components/Empty";
import Icon from "@/components/Icon";
import MemoContent from "@/components/MemoContent";
import MemoFilters from "@/components/MemoFilters";
import MobileHeader from "@/components/MobileHeader";
@ -97,7 +97,7 @@ const Archived = () => {
<div className="w-full flex flex-col justify-start items-start">
<div className="w-full flex flex-row justify-between items-center mb-2">
<div className="flex flex-row justify-start items-center gap-1">
<Icon.Archive className="w-5 h-auto opacity-70 shrink-0" />
<ArchiveIcon className="w-5 h-auto opacity-70 shrink-0" />
<span>{t("common.archived")}</span>
</div>
<div className="w-44">
@ -119,12 +119,12 @@ const Archived = () => {
<div className="flex flex-row justify-end items-center gap-x-2">
<Tooltip title={t("common.restore")} placement="top">
<button onClick={() => handleRestoreMemoClick(memo)}>
<Icon.ArchiveRestore className="w-4 h-auto cursor-pointer text-gray-500 dark:text-gray-400" />
<ArchiveRestoreIcon className="w-4 h-auto cursor-pointer text-gray-500 dark:text-gray-400" />
</button>
</Tooltip>
<Tooltip title={t("common.delete")} placement="top">
<button onClick={() => handleDeleteMemoClick(memo)} className="text-gray-500 dark:text-gray-400">
<Icon.Trash className="w-4 h-auto cursor-pointer" />
<TrashIcon className="w-4 h-auto cursor-pointer" />
</button>
</Tooltip>
</div>
@ -138,7 +138,7 @@ const Archived = () => {
variant="plain"
color="neutral"
loading={isRequesting}
endDecorator={<Icon.ArrowDown className="w-4 h-auto" />}
endDecorator={<ArrowDownIcon className="w-4 h-auto" />}
onClick={() => fetchMemos(nextPageToken)}
>
{t("memo.load-more")}

View File

@ -1,8 +1,8 @@
import { last } from "lodash-es";
import { LoaderIcon } from "lucide-react";
import { ClientError } from "nice-grpc-web";
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import Icon from "@/components/Icon";
import { authServiceClient } from "@/grpcweb";
import { absolutifyLink } from "@/helpers/utils";
import useNavigateTo from "@/hooks/useNavigateTo";
@ -70,7 +70,7 @@ const AuthCallback = () => {
return (
<div className="p-4 py-24 w-full h-full flex justify-center items-center">
{state.loading ? (
<Icon.Loader className="animate-spin dark:text-gray-200" />
<LoaderIcon className="animate-spin dark:text-gray-200" />
) : (
<div className="max-w-lg font-mono whitespace-pre-wrap opacity-80">{state.errorMessage}</div>
)}

View File

@ -1,10 +1,10 @@
import { Button } from "@mui/joy";
import clsx from "clsx";
import dayjs from "dayjs";
import { ArrowDownIcon } from "lucide-react";
import { useEffect, useState } from "react";
import Empty from "@/components/Empty";
import { ExploreSidebar, ExploreSidebarDrawer } from "@/components/ExploreSidebar";
import Icon from "@/components/Icon";
import MemoFilters from "@/components/MemoFilters";
import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader";
@ -84,7 +84,7 @@ const Explore = () => {
variant="plain"
color="neutral"
loading={isRequesting}
endDecorator={<Icon.ArrowDown className="w-4 h-auto" />}
endDecorator={<ArrowDownIcon className="w-4 h-auto" />}
onClick={() => fetchMemos(nextPageToken)}
>
{t("memo.load-more")}

View File

@ -1,10 +1,10 @@
import { Button } from "@mui/joy";
import clsx from "clsx";
import dayjs from "dayjs";
import { ArrowDownIcon } from "lucide-react";
import { useEffect, useState } from "react";
import Empty from "@/components/Empty";
import { HomeSidebar, HomeSidebarDrawer } from "@/components/HomeSidebar";
import Icon from "@/components/Icon";
import MemoEditor from "@/components/MemoEditor";
import MemoFilters from "@/components/MemoFilters";
import MemoView from "@/components/MemoView";
@ -100,7 +100,7 @@ const Home = () => {
variant="plain"
color="neutral"
loading={isRequesting}
endDecorator={<Icon.ArrowDown className="w-4 h-auto" />}
endDecorator={<ArrowDownIcon className="w-4 h-auto" />}
onClick={() => fetchMemos(nextPageToken)}
>
{t("memo.load-more")}

View File

@ -1,6 +1,6 @@
import { BellIcon } from "lucide-react";
import { useEffect } from "react";
import Empty from "@/components/Empty";
import Icon from "@/components/Icon";
import MemoCommentMessage from "@/components/Inbox/MemoCommentMessage";
import VersionUpdateMessage from "@/components/Inbox/VersionUpdateMessage";
import MobileHeader from "@/components/MobileHeader";
@ -29,7 +29,7 @@ const Inboxes = () => {
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300">
<div className="relative w-full flex flex-row justify-between items-center">
<p className="py-1 flex flex-row justify-start items-center select-none opacity-80">
<Icon.Bell className="w-6 h-auto mr-1 opacity-80" />
<BellIcon className="w-6 h-auto mr-1 opacity-80" />
<span className="text-lg">{t("common.inbox")}</span>
</p>
</div>

View File

@ -1,10 +1,10 @@
import Icon from "@/components/Icon";
import { LoaderIcon } from "lucide-react";
function Loading() {
return (
<div className="fixed w-full h-full flex flex-row justify-center items-center">
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-center items-center">
<Icon.Loader className="animate-spin dark:text-gray-200" />
<LoaderIcon className="animate-spin dark:text-gray-200" />
</div>
</div>
);

View File

@ -1,10 +1,10 @@
import { Button } from "@mui/joy";
import clsx from "clsx";
import { ArrowUpLeftFromCircleIcon, MessageCircleIcon } from "lucide-react";
import { ClientError } from "nice-grpc-web";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { Link, useParams } from "react-router-dom";
import Icon from "@/components/Icon";
import { MemoDetailSidebar, MemoDetailSidebarDrawer } from "@/components/MemoDetailSidebar";
import MemoEditor from "@/components/MemoEditor";
import MemoView from "@/components/MemoView";
@ -98,7 +98,7 @@ const MemoDetail = () => {
to={`/m/${parentMemo.uid}`}
unstable_viewTransition
>
<Icon.ArrowUpLeftFromCircle className="w-4 h-auto shrink-0 opacity-60 mr-2" />
<ArrowUpLeftFromCircleIcon className="w-4 h-auto shrink-0 opacity-60 mr-2" />
<span className="truncate">{parentMemo.content}</span>
</Link>
</div>
@ -123,7 +123,7 @@ const MemoDetail = () => {
<Button
variant="plain"
color="neutral"
endDecorator={<Icon.MessageCircle className="w-5 h-auto text-gray-500" />}
endDecorator={<MessageCircleIcon className="w-5 h-auto text-gray-500" />}
onClick={handleShowCommentEditor}
>
<span className="font-normal text-gray-500">{t("memo.comment.write-a-comment")}</span>
@ -134,7 +134,7 @@ const MemoDetail = () => {
<>
<div className="w-full flex flex-row justify-between items-center px-3 mb-2">
<div className="flex flex-row justify-start items-center">
<Icon.MessageCircle className="w-5 h-auto text-gray-400 mr-1" />
<MessageCircleIcon 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-1">({comments.length})</span>
</div>

View File

@ -1,9 +1,9 @@
import { Divider, IconButton, Input, Tooltip } from "@mui/joy";
import dayjs from "dayjs";
import { includes } from "lodash-es";
import { PaperclipIcon, SearchIcon, TrashIcon } from "lucide-react";
import { useEffect, useState } from "react";
import Empty from "@/components/Empty";
import Icon from "@/components/Icon";
import MobileHeader from "@/components/MobileHeader";
import ResourceIcon from "@/components/ResourceIcon";
import { resourceServiceClient } from "@/grpcweb";
@ -68,14 +68,14 @@ const Resources = () => {
<div className="w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300">
<div className="relative w-full flex flex-row justify-between items-center">
<p className="py-1 flex flex-row justify-start items-center select-none opacity-80">
<Icon.Paperclip className="w-6 h-auto mr-1 opacity-80" />
<PaperclipIcon className="w-6 h-auto mr-1 opacity-80" />
<span className="text-lg">{t("common.resources")}</span>
</p>
<div>
<Input
className="max-w-[8rem]"
placeholder={t("common.search")}
startDecorator={<Icon.Search className="w-4 h-auto" />}
startDecorator={<SearchIcon className="w-4 h-auto" />}
value={state.searchQuery}
onChange={(e) => setState({ ...state, searchQuery: e.target.value })}
/>
@ -133,7 +133,7 @@ const Resources = () => {
<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" />
<TrashIcon className="w-4 h-auto opacity-60" />
</IconButton>
</Tooltip>
</div>

View File

@ -1,7 +1,6 @@
import { Option, Select } from "@mui/joy";
import { LucideIcon } from "lucide-react";
import { CogIcon, DatabaseIcon, KeyIcon, LibraryIcon, LucideIcon, Settings2Icon, UserIcon, UsersIcon } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import Icon from "@/components/Icon";
import MobileHeader from "@/components/MobileHeader";
import MemberSection from "@/components/Settings/MemberSection";
import MemoRelatedSettings from "@/components/Settings/MemoRelatedSettings";
@ -27,13 +26,13 @@ interface State {
const BASIC_SECTIONS: SettingSection[] = ["my-account", "preference"];
const ADMIN_SECTIONS: SettingSection[] = ["member", "system", "memo-related", "storage", "sso"];
const SECTION_ICON_MAP: Record<SettingSection, LucideIcon> = {
"my-account": Icon.User,
preference: Icon.Cog,
member: Icon.Users,
system: Icon.Settings2,
"memo-related": Icon.Library,
storage: Icon.Database,
sso: Icon.Key,
"my-account": UserIcon,
preference: CogIcon,
member: UsersIcon,
system: Settings2Icon,
"memo-related": LibraryIcon,
storage: DatabaseIcon,
sso: KeyIcon,
};
const Setting = () => {

View File

@ -1,11 +1,11 @@
import { Button } from "@mui/joy";
import copy from "copy-to-clipboard";
import dayjs from "dayjs";
import { ArrowDownIcon, ExternalLinkIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { useParams } from "react-router-dom";
import Empty from "@/components/Empty";
import Icon from "@/components/Icon";
import MemoFilters from "@/components/MemoFilters";
import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader";
@ -113,7 +113,7 @@ const UserProfile = () => {
<Button
color="neutral"
variant="outlined"
endDecorator={<Icon.ExternalLink className="w-4 h-auto opacity-60" />}
endDecorator={<ExternalLinkIcon className="w-4 h-auto opacity-60" />}
onClick={handleCopyProfileLink}
>
{t("common.share")}
@ -140,7 +140,7 @@ const UserProfile = () => {
variant="plain"
color="neutral"
loading={isRequesting}
endDecorator={<Icon.ArrowDown className="w-4 h-auto" />}
endDecorator={<ArrowDownIcon className="w-4 h-auto" />}
onClick={() => fetchMemos(nextPageToken)}
>
{t("memo.load-more")}