UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: латинский URL workspace
This commit is contained in:
parent
268ab2c9b9
commit
a86ed9f5f3
|
|
@ -16,6 +16,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IUser, IWorkspace } from "@plane/types";
|
import type { IUser, IWorkspace } from "@plane/types";
|
||||||
import { Spinner } from "@plane/ui";
|
import { Spinner } from "@plane/ui";
|
||||||
import { cn, validateWorkspaceName, validateSlug } from "@plane/utils";
|
import { cn, validateWorkspaceName, validateSlug } from "@plane/utils";
|
||||||
|
import { createWorkspaceSlug } from "@/helpers/workspace-slug";
|
||||||
// hooks
|
// hooks
|
||||||
import { useInstance } from "@/hooks/store/use-instance";
|
import { useInstance } from "@/hooks/store/use-instance";
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
|
|
@ -160,7 +161,7 @@ export const WorkspaceCreateStep = observer(function WorkspaceCreateStep({
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
onChange(event.target.value);
|
onChange(event.target.value);
|
||||||
setValue("name", event.target.value);
|
setValue("name", event.target.value);
|
||||||
setValue("slug", event.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"), {
|
setValue("slug", createWorkspaceSlug(event.target.value), {
|
||||||
shouldValidate: true,
|
shouldValidate: true,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
@ -215,12 +216,13 @@ export const WorkspaceCreateStep = observer(function WorkspaceCreateStep({
|
||||||
id="slug"
|
id="slug"
|
||||||
name="slug"
|
name="slug"
|
||||||
type="text"
|
type="text"
|
||||||
value={value.toLocaleLowerCase().trim().replace(/ /g, "-")}
|
value={createWorkspaceSlug(value)}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const validation = validateSlug(e.target.value);
|
const nextSlug = createWorkspaceSlug(e.target.value);
|
||||||
|
const validation = validateSlug(nextSlug);
|
||||||
if (validation === true) setInvalidSlug(false);
|
if (validation === true) setInvalidSlug(false);
|
||||||
else setInvalidSlug(true);
|
else setInvalidSlug(true);
|
||||||
onChange(e.target.value.toLowerCase());
|
onChange(nextSlug);
|
||||||
}}
|
}}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
placeholder={t("workspace_creation.form.url.placeholder")}
|
placeholder={t("workspace_creation.form.url.placeholder")}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import type { IWorkspace } from "@plane/types";
|
||||||
import { Input } from "@plane/ui";
|
import { Input } from "@plane/ui";
|
||||||
import { validateWorkspaceName, validateSlug } from "@plane/utils";
|
import { validateWorkspaceName, validateSlug } from "@plane/utils";
|
||||||
import { SelectionDropdown } from "@/components/common/selection-dropdown";
|
import { SelectionDropdown } from "@/components/common/selection-dropdown";
|
||||||
|
import { createWorkspaceSlug } from "@/helpers/workspace-slug";
|
||||||
// hooks
|
// hooks
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
@ -61,7 +62,7 @@ export const CreateWorkspaceForm = observer(function CreateWorkspaceForm(props:
|
||||||
const inputShellClassName = isNodeDCAuth ? "nodedc-auth-input-shell flex w-full items-center px-4" : "flex flex-col gap-1";
|
const inputShellClassName = isNodeDCAuth ? "nodedc-auth-input-shell flex w-full items-center px-4" : "flex flex-col gap-1";
|
||||||
const inputClassName = isNodeDCAuth ? "nodedc-auth-input h-12 w-full px-0 py-0 text-14" : "w-full";
|
const inputClassName = isNodeDCAuth ? "nodedc-auth-input h-12 w-full px-0 py-0 text-14" : "w-full";
|
||||||
const urlShellClassName = isNodeDCAuth
|
const urlShellClassName = isNodeDCAuth
|
||||||
? "nodedc-auth-input-shell flex w-full items-center px-4"
|
? "nodedc-auth-input-shell flex w-full items-center px-4 text-14"
|
||||||
: "flex w-full items-center rounded-md border border-subtle bg-layer-2 px-3";
|
: "flex w-full items-center rounded-md border border-subtle bg-layer-2 px-3";
|
||||||
const urlInputClassName = isNodeDCAuth
|
const urlInputClassName = isNodeDCAuth
|
||||||
? "nodedc-auth-input block h-12 w-full border-none bg-transparent !px-0 py-0 text-14"
|
? "nodedc-auth-input block h-12 w-full border-none bg-transparent !px-0 py-0 text-14"
|
||||||
|
|
@ -161,7 +162,7 @@ export const CreateWorkspaceForm = observer(function CreateWorkspaceForm(props:
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
setValue("name", e.target.value);
|
setValue("name", e.target.value);
|
||||||
setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"), {
|
setValue("slug", createWorkspaceSlug(e.target.value), {
|
||||||
shouldValidate: true,
|
shouldValidate: true,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
@ -181,7 +182,9 @@ export const CreateWorkspaceForm = observer(function CreateWorkspaceForm(props:
|
||||||
{requiredMark}
|
{requiredMark}
|
||||||
</label>
|
</label>
|
||||||
<div className={urlShellClassName} data-error={Boolean(errors.slug) || slugError || invalidSlug}>
|
<div className={urlShellClassName} data-error={Boolean(errors.slug) || slugError || invalidSlug}>
|
||||||
<span className="mr-1 text-12 whitespace-nowrap text-secondary">{window && window.location.host}/</span>
|
<span className={isNodeDCAuth ? "mr-1 whitespace-nowrap text-secondary" : "mr-1 text-12 whitespace-nowrap text-secondary"}>
|
||||||
|
{window && window.location.host}/
|
||||||
|
</span>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="slug"
|
name="slug"
|
||||||
|
|
@ -196,12 +199,13 @@ export const CreateWorkspaceForm = observer(function CreateWorkspaceForm(props:
|
||||||
<Input
|
<Input
|
||||||
id="workspaceUrl"
|
id="workspaceUrl"
|
||||||
type="text"
|
type="text"
|
||||||
value={value.toLocaleLowerCase().trim().replace(/ /g, "-")}
|
value={createWorkspaceSlug(value)}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const validation = validateSlug(e.target.value);
|
const nextSlug = createWorkspaceSlug(e.target.value);
|
||||||
|
const validation = validateSlug(nextSlug);
|
||||||
if (validation === true) setInvalidSlug(false);
|
if (validation === true) setInvalidSlug(false);
|
||||||
else setInvalidSlug(true);
|
else setInvalidSlug(true);
|
||||||
onChange(e.target.value.toLowerCase());
|
onChange(nextSlug);
|
||||||
}}
|
}}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
hasError={Boolean(errors.slug)}
|
hasError={Boolean(errors.slug)}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
const CYRILLIC_TO_LATIN: Record<string, string> = {
|
||||||
|
а: "a",
|
||||||
|
б: "b",
|
||||||
|
в: "v",
|
||||||
|
г: "g",
|
||||||
|
д: "d",
|
||||||
|
е: "e",
|
||||||
|
ё: "e",
|
||||||
|
ж: "zh",
|
||||||
|
з: "z",
|
||||||
|
и: "i",
|
||||||
|
й: "y",
|
||||||
|
к: "k",
|
||||||
|
л: "l",
|
||||||
|
м: "m",
|
||||||
|
н: "n",
|
||||||
|
о: "o",
|
||||||
|
п: "p",
|
||||||
|
р: "r",
|
||||||
|
с: "s",
|
||||||
|
т: "t",
|
||||||
|
у: "u",
|
||||||
|
ф: "f",
|
||||||
|
х: "kh",
|
||||||
|
ц: "ts",
|
||||||
|
ч: "ch",
|
||||||
|
ш: "sh",
|
||||||
|
щ: "shch",
|
||||||
|
ъ: "",
|
||||||
|
ы: "y",
|
||||||
|
ь: "",
|
||||||
|
э: "e",
|
||||||
|
ю: "yu",
|
||||||
|
я: "ya",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createWorkspaceSlug = (value: string) =>
|
||||||
|
value
|
||||||
|
.trim()
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.split("")
|
||||||
|
.map((character) => CYRILLIC_TO_LATIN[character] ?? character)
|
||||||
|
.join("")
|
||||||
|
.normalize("NFKD")
|
||||||
|
.replace(/[\u0300-\u036f]/g, "")
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/^-+|-+$/g, "")
|
||||||
|
.replace(/-{2,}/g, "-");
|
||||||
Loading…
Reference in New Issue