mirror of
https://github.com/usememos/memos.git
synced 2024-12-20 01:31:29 +03:00
fix: visibility translation (#2429)
* fix: visibility translation * refactor: remove useless file * feat: add visibility icon
This commit is contained in:
parent
82effea070
commit
035d71e07c
@ -1,41 +0,0 @@
|
|||||||
import { toLower } from "lodash-es";
|
|
||||||
import Selector from "@/components/kit/Selector";
|
|
||||||
import { VISIBILITY_SELECTOR_ITEMS } from "@/helpers/consts";
|
|
||||||
import { useGlobalStore } from "@/store/module";
|
|
||||||
import { useTranslate } from "@/utils/i18n";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
value: Visibility;
|
|
||||||
onChange: (value: Visibility) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MemoVisibilitySelector = (props: Props) => {
|
|
||||||
const { value, onChange } = props;
|
|
||||||
const t = useTranslate();
|
|
||||||
const {
|
|
||||||
state: { systemStatus },
|
|
||||||
} = useGlobalStore();
|
|
||||||
const memoVisibilityOptionSelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => {
|
|
||||||
return {
|
|
||||||
value: item.value,
|
|
||||||
text: t(`memo.visibility.${toLower(item.value) as Lowercase<typeof item.value>}`),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleMemoVisibilityOptionChanged = async (visibility: string) => {
|
|
||||||
onChange(visibility as Visibility);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Selector
|
|
||||||
className="visibility-selector"
|
|
||||||
disabled={systemStatus.disablePublicMemos}
|
|
||||||
tooltipTitle={t("memo.visibility.disabled")}
|
|
||||||
value={value}
|
|
||||||
dataSource={memoVisibilityOptionSelectorItems}
|
|
||||||
handleValueChanged={handleMemoVisibilityOptionChanged}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MemoVisibilitySelector;
|
|
@ -462,8 +462,8 @@ const MemoEditor = (props: Props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
||||||
<Option key={item.value} value={item.value} className="whitespace-nowrap">
|
<Option key={item} value={item} className="whitespace-nowrap">
|
||||||
{item.text}
|
{t(`memo.visibility.${item.toLowerCase() as Lowercase<typeof item>}`)}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -7,6 +7,7 @@ import { useTranslate } from "@/utils/i18n";
|
|||||||
import AppearanceSelect from "../AppearanceSelect";
|
import AppearanceSelect from "../AppearanceSelect";
|
||||||
import LearnMore from "../LearnMore";
|
import LearnMore from "../LearnMore";
|
||||||
import LocaleSelect from "../LocaleSelect";
|
import LocaleSelect from "../LocaleSelect";
|
||||||
|
import VisibilityIcon from "../VisibilityIcon";
|
||||||
import "@/less/settings/preferences-section.less";
|
import "@/less/settings/preferences-section.less";
|
||||||
|
|
||||||
const PreferencesSection = () => {
|
const PreferencesSection = () => {
|
||||||
@ -16,12 +17,6 @@ const PreferencesSection = () => {
|
|||||||
const { appearance, locale } = globalStore.state;
|
const { appearance, locale } = globalStore.state;
|
||||||
const { setting, localSetting } = userStore.state.user as User;
|
const { setting, localSetting } = userStore.state.user as User;
|
||||||
const [telegramUserId, setTelegramUserId] = useState<string>(setting.telegramUserId);
|
const [telegramUserId, setTelegramUserId] = useState<string>(setting.telegramUserId);
|
||||||
const visibilitySelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => {
|
|
||||||
return {
|
|
||||||
value: item.value,
|
|
||||||
text: t(`memo.visibility.${item.value.toLowerCase() as Lowercase<typeof item.value>}`),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const dailyReviewTimeOffsetOptions: number[] = [...Array(24).keys()];
|
const dailyReviewTimeOffsetOptions: number[] = [...Array(24).keys()];
|
||||||
|
|
||||||
@ -78,15 +73,16 @@ const PreferencesSection = () => {
|
|||||||
<Select
|
<Select
|
||||||
className="!min-w-fit"
|
className="!min-w-fit"
|
||||||
value={setting.memoVisibility}
|
value={setting.memoVisibility}
|
||||||
|
startDecorator={<VisibilityIcon visibility={setting.memoVisibility} />}
|
||||||
onChange={(_, visibility) => {
|
onChange={(_, visibility) => {
|
||||||
if (visibility) {
|
if (visibility) {
|
||||||
handleDefaultMemoVisibilityChanged(visibility);
|
handleDefaultMemoVisibilityChanged(visibility);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{visibilitySelectorItems.map((item) => (
|
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
||||||
<Option key={item.value} value={item.value}>
|
<Option key={item} value={item} className="whitespace-nowrap">
|
||||||
{item.text}
|
{t(`memo.visibility.${item.toLowerCase() as Lowercase<typeof item>}`)}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
import { Tooltip } from "@mui/joy";
|
|
||||||
import { memo, useEffect, useRef } from "react";
|
|
||||||
import useToggle from "react-use/lib/useToggle";
|
|
||||||
import { useTranslate } from "@/utils/i18n";
|
|
||||||
import Icon from "../Icon";
|
|
||||||
import "@/less/common/selector.less";
|
|
||||||
|
|
||||||
interface SelectorItem {
|
|
||||||
text: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
className?: string;
|
|
||||||
value: string;
|
|
||||||
dataSource: SelectorItem[];
|
|
||||||
handleValueChanged?: (value: string) => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
tooltipTitle?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nullItem = {
|
|
||||||
text: "common.select" as const,
|
|
||||||
value: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
const Selector: React.FC<Props> = (props: Props) => {
|
|
||||||
const { className, dataSource, handleValueChanged, value, disabled, tooltipTitle } = props;
|
|
||||||
const t = useTranslate();
|
|
||||||
const [showSelector, toggleSelectorStatus] = useToggle(false);
|
|
||||||
|
|
||||||
const selectorElRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
let currentItem = { text: t(nullItem.text), value: nullItem.value };
|
|
||||||
for (const d of dataSource) {
|
|
||||||
if (d.value === value) {
|
|
||||||
currentItem = d;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (showSelector) {
|
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
|
||||||
if (!selectorElRef.current?.contains(event.target as Node)) {
|
|
||||||
toggleSelectorStatus(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
window.addEventListener("click", handleClickOutside, {
|
|
||||||
capture: true,
|
|
||||||
once: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [showSelector]);
|
|
||||||
|
|
||||||
const handleItemClick = (item: SelectorItem) => {
|
|
||||||
if (handleValueChanged) {
|
|
||||||
handleValueChanged(item.value);
|
|
||||||
}
|
|
||||||
toggleSelectorStatus(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCurrentValueClick = (event: React.MouseEvent) => {
|
|
||||||
if (disabled) return;
|
|
||||||
event.stopPropagation();
|
|
||||||
toggleSelectorStatus();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip title={tooltipTitle} hidden={!disabled}>
|
|
||||||
<div className={`selector-wrapper ${className ?? ""} `} ref={selectorElRef}>
|
|
||||||
<div
|
|
||||||
className={`current-value-container ${showSelector ? "active" : ""} ${disabled && "selector-disabled"}`}
|
|
||||||
onClick={handleCurrentValueClick}
|
|
||||||
>
|
|
||||||
{disabled && (
|
|
||||||
<span className="lock-text">
|
|
||||||
<Icon.Lock className="icon-img" />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<span className="value-text">{currentItem.text}</span>
|
|
||||||
{!disabled && (
|
|
||||||
<span className="arrow-text">
|
|
||||||
<Icon.ChevronDown className="icon-img" />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={`items-wrapper ${showSelector ? "" : "!hidden"}`}>
|
|
||||||
{dataSource.length > 0 ? (
|
|
||||||
dataSource.map((d) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`item-container ${d.value === value ? "selected" : ""}`}
|
|
||||||
key={d.value}
|
|
||||||
onClick={() => {
|
|
||||||
handleItemClick(d);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{d.text}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
) : (
|
|
||||||
<p className="tip-text">{t("common.null")}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(Selector);
|
|
@ -7,11 +7,7 @@ export const ANIMATION_DURATION = 200;
|
|||||||
// millisecond in a day
|
// millisecond in a day
|
||||||
export const DAILY_TIMESTAMP = 3600 * 24 * 1000;
|
export const DAILY_TIMESTAMP = 3600 * 24 * 1000;
|
||||||
|
|
||||||
export const VISIBILITY_SELECTOR_ITEMS = [
|
export const VISIBILITY_SELECTOR_ITEMS = ["PRIVATE", "PROTECTED", "PUBLIC"] as const;
|
||||||
{ text: "Private", value: "PRIVATE" },
|
|
||||||
{ text: "Workspace", value: "PROTECTED" },
|
|
||||||
{ text: "Public", value: "PUBLIC" },
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
// space width for tab action in editor
|
// space width for tab action in editor
|
||||||
export const TAB_SPACE_WIDTH = 2;
|
export const TAB_SPACE_WIDTH = 2;
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
.selector-wrapper {
|
|
||||||
@apply flex flex-col justify-start items-start relative h-8;
|
|
||||||
|
|
||||||
> .current-value-container {
|
|
||||||
@apply flex flex-row justify-between items-center w-full h-full rounded px-2 pr-1 bg-white dark:bg-zinc-700 dark:border-zinc-600 border cursor-pointer select-none;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&.active {
|
|
||||||
@apply bg-gray-100 dark:bg-zinc-700;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .value-text {
|
|
||||||
@apply text-sm mr-0 truncate dark:text-gray-300;
|
|
||||||
width: calc(100% - 20px);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .lock-text {
|
|
||||||
@apply flex flex-row justify-center items-center w-4 shrink-0 mr-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .arrow-text {
|
|
||||||
@apply flex flex-row justify-center items-center w-4 shrink-0;
|
|
||||||
|
|
||||||
> .icon-img {
|
|
||||||
@apply w-4 h-auto opacity-40 dark:text-gray-300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .items-wrapper {
|
|
||||||
@apply flex flex-col justify-start items-start absolute top-full left-0 w-auto p-1 mt-1 -ml-2 bg-white dark:bg-zinc-800 dark:border-zinc-600 rounded-md overflow-y-auto z-1 hide-scrollbar;
|
|
||||||
min-width: calc(100% + 16px);
|
|
||||||
max-height: 256px;
|
|
||||||
box-shadow: 0 0 8px 0 rgb(0 0 0 / 20%);
|
|
||||||
|
|
||||||
> .item-container {
|
|
||||||
@apply flex flex-col justify-start items-start w-full px-3 text-sm select-none leading-8 cursor-pointer rounded whitespace-nowrap dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-zinc-600;
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
@apply text-green-600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .tip-text {
|
|
||||||
@apply px-3 py-1 text-sm text-gray-600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .selector-disabled {
|
|
||||||
@apply cursor-not-allowed;
|
|
||||||
@apply pointer-events-none;
|
|
||||||
|
|
||||||
@apply bg-gray-200 dark:bg-zinc-700 dark:border-zinc-600 text-gray-400;
|
|
||||||
}
|
|
||||||
}
|
|
@ -156,8 +156,8 @@ const MemoDetail = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
{VISIBILITY_SELECTOR_ITEMS.map((item) => (
|
||||||
<Option key={item.value} value={item.value} className="whitespace-nowrap">
|
<Option key={item} value={item} className="whitespace-nowrap">
|
||||||
{item.text}
|
{t(`memo.visibility.${item.toLowerCase() as Lowercase<typeof item>}`)}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
Loading…
Reference in New Issue
Block a user