forked from github/plane
[WEB-1119] style: editor typography, borders and alignment throughout the platform (#4322)
* chore: new font sizes * chore: update space app editor border * chore: issue detials page x-padding * chore: editor width
This commit is contained in:
parent
2e2747c1f9
commit
ed4a0518fc
@ -1,3 +1,14 @@
|
|||||||
|
.ProseMirror {
|
||||||
|
--font-size-h1: 1.5rem;
|
||||||
|
--font-size-h2: 1.3125rem;
|
||||||
|
--font-size-h3: 1.125rem;
|
||||||
|
--font-size-h4: 0.9375rem;
|
||||||
|
--font-size-h5: 0.8125rem;
|
||||||
|
--font-size-h6: 0.75rem;
|
||||||
|
--font-size-regular: 0.9375rem;
|
||||||
|
--font-size-list: var(--font-size-regular);
|
||||||
|
}
|
||||||
|
|
||||||
.ProseMirror p.is-editor-empty:first-child::before {
|
.ProseMirror p.is-editor-empty:first-child::before {
|
||||||
content: attr(data-placeholder);
|
content: attr(data-placeholder);
|
||||||
float: left;
|
float: left;
|
||||||
@ -56,7 +67,7 @@
|
|||||||
|
|
||||||
/* to-do list */
|
/* to-do list */
|
||||||
ul[data-type="taskList"] li {
|
ul[data-type="taskList"] li {
|
||||||
font-size: 1rem;
|
font-size: var(--font-size-list);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +173,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
cursor: text;
|
cursor: text;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 14px;
|
font-size: var(--font-size-regular);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -310,15 +321,15 @@ ul[data-type="taskList"] ul[data-type="taskList"] {
|
|||||||
.prose :where(h1):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(h1):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: 1.875rem;
|
font-size: var(--font-size-h1);
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose :where(h2):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(h2):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 1.4rem;
|
margin-top: 1.4rem;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
font-size: 1.5rem;
|
font-size: var(--font-size-h2);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
@ -326,21 +337,23 @@ ul[data-type="taskList"] ul[data-type="taskList"] {
|
|||||||
.prose :where(h3):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(h3):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
font-size: 1.25rem;
|
font-size: var(--font-size-h3);
|
||||||
|
font-weight: 600;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose :where(h4):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(h4):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
font-size: 1rem;
|
font-size: var(--font-size-h4);
|
||||||
|
font-weight: 600;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose :where(h5):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(h5):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
font-size: 0.9rem;
|
font-size: var(--font-size-h5);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
@ -348,7 +361,7 @@ ul[data-type="taskList"] ul[data-type="taskList"] {
|
|||||||
.prose :where(h6):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(h6):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
font-size: 0.83rem;
|
font-size: var(--font-size-h6);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
@ -356,14 +369,14 @@ ul[data-type="taskList"] ul[data-type="taskList"] {
|
|||||||
.prose :where(p):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(p):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
margin-top: 0.25rem;
|
margin-top: 0.25rem;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
padding: 3px 2px;
|
padding: 3px 0;
|
||||||
font-size: 1rem;
|
font-size: var(--font-size-regular);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose :where(ol):not(:where([class~="not-prose"], [class~="not-prose"] *)) li p,
|
.prose :where(ol):not(:where([class~="not-prose"], [class~="not-prose"] *)) li p,
|
||||||
.prose :where(ul):not(:where([class~="not-prose"], [class~="not-prose"] *)) li p {
|
.prose :where(ul):not(:where([class~="not-prose"], [class~="not-prose"] *)) li p {
|
||||||
font-size: 1rem;
|
font-size: var(--font-size-list);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, Ric
|
|||||||
mentionHandler={{ highlights: mentionHighlights }}
|
mentionHandler={{ highlights: mentionHighlights }}
|
||||||
{...props}
|
{...props}
|
||||||
// overriding the customClassName to add relative class passed
|
// overriding the customClassName to add relative class passed
|
||||||
containerClassName={cn(props.containerClassName, "relative border border-custom-border-200 p-3")}
|
containerClassName={cn("relative p-0 border-none", props.containerClassName)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
|
|||||||
suggestions: mentionSuggestions,
|
suggestions: mentionSuggestions,
|
||||||
}}
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
containerClassName={cn(containerClassName, "relative min-h-[150px] border border-custom-border-200 p-3")}
|
containerClassName={cn("relative min-h-[150px] pl-3", containerClassName)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,7 @@ export const InboxIssueContentProperties: React.FC<Props> = observer((props) =>
|
|||||||
if (!issue || !issue?.id) return <></>;
|
if (!issue || !issue?.id) return <></>;
|
||||||
return (
|
return (
|
||||||
<div className="flex h-min w-full flex-col divide-y-2 divide-custom-border-200 overflow-hidden">
|
<div className="flex h-min w-full flex-col divide-y-2 divide-custom-border-200 overflow-hidden">
|
||||||
<div className="h-min w-full overflow-y-auto px-5">
|
<div className="h-min w-full overflow-y-auto px-3">
|
||||||
<h5 className="text-sm font-medium my-4">Properties</h5>
|
<h5 className="text-sm font-medium my-4">Properties</h5>
|
||||||
<div className={`divide-y-2 divide-custom-border-200 ${!isEditable ? "opacity-60" : ""}`}>
|
<div className={`divide-y-2 divide-custom-border-200 ${!isEditable ? "opacity-60" : ""}`}>
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
|
@ -114,7 +114,7 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="rounded-lg space-y-4">
|
<div className="rounded-lg space-y-4 pl-3">
|
||||||
<IssueTitleInput
|
<IssueTitleInput
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
projectId={issue.project_id}
|
projectId={issue.project_id}
|
||||||
@ -124,6 +124,7 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
issueOperations={issueOperations}
|
issueOperations={issueOperations}
|
||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
value={issue.name}
|
value={issue.name}
|
||||||
|
containerClassName="-ml-3"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{loader === "issue-loading" ? (
|
{loader === "issue-loading" ? (
|
||||||
@ -140,6 +141,7 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
issueOperations={issueOperations}
|
issueOperations={issueOperations}
|
||||||
setIsSubmitting={(value) => setIsSubmitting(value)}
|
setIsSubmitting={(value) => setIsSubmitting(value)}
|
||||||
|
containerClassName="-ml-3 border-none"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -152,12 +154,15 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<IssueAttachmentRoot
|
|
||||||
workspaceSlug={workspaceSlug}
|
<div className="pl-3">
|
||||||
projectId={projectId}
|
<IssueAttachmentRoot
|
||||||
issueId={issue.id}
|
workspaceSlug={workspaceSlug}
|
||||||
disabled={!isEditable}
|
projectId={projectId}
|
||||||
/>
|
issueId={issue.id}
|
||||||
|
disabled={!isEditable}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<InboxIssueContentProperties
|
<InboxIssueContentProperties
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
@ -168,7 +173,7 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
duplicateIssueDetails={inboxIssue?.duplicate_issue_detail}
|
duplicateIssueDetails={inboxIssue?.duplicate_issue_detail}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="pb-12">
|
<div className="pb-12 pl-3">
|
||||||
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issue.id} />
|
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issue.id} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -52,7 +52,7 @@ export const InboxContentRoot: FC<TInboxContentRoot> = observer((props) => {
|
|||||||
isSubmitting={isSubmitting}
|
isSubmitting={isSubmitting}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full w-full space-y-5 divide-y-2 divide-custom-border-300 overflow-y-auto p-5 vertical-scrollbar scrollbar-md">
|
<div className="h-full w-full space-y-5 divide-y-2 divide-custom-border-200 overflow-y-auto px-6 py-5 vertical-scrollbar scrollbar-md">
|
||||||
<InboxIssueMainContent
|
<InboxIssueMainContent
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
@ -133,6 +133,7 @@ export const InboxIssueCreateRoot: FC<TInboxIssueCreateRoot> = observer((props)
|
|||||||
data={formData}
|
data={formData}
|
||||||
handleData={handleFormData}
|
handleData={handleFormData}
|
||||||
editorRef={descriptionEditorRef}
|
editorRef={descriptionEditorRef}
|
||||||
|
containerClassName="border-[0.5px] border-custom-border-200 py-3"
|
||||||
/>
|
/>
|
||||||
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} />
|
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} />
|
||||||
<div className="relative flex justify-between items-center gap-3">
|
<div className="relative flex justify-between items-center gap-3">
|
||||||
|
@ -138,6 +138,7 @@ export const InboxIssueEditRoot: FC<TInboxIssueEditRoot> = observer((props) => {
|
|||||||
data={formData}
|
data={formData}
|
||||||
handleData={handleFormData}
|
handleData={handleFormData}
|
||||||
editorRef={descriptionEditorRef}
|
editorRef={descriptionEditorRef}
|
||||||
|
containerClassName="border-[0.5px] border-custom-border-200 py-3"
|
||||||
/>
|
/>
|
||||||
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} isVisible />
|
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} isVisible />
|
||||||
<div className="relative flex justify-end items-center gap-3">
|
<div className="relative flex justify-end items-center gap-3">
|
||||||
|
@ -11,6 +11,7 @@ import { getDescriptionPlaceholder } from "@/helpers/issue.helper";
|
|||||||
import { useProjectInbox } from "@/hooks/store";
|
import { useProjectInbox } from "@/hooks/store";
|
||||||
|
|
||||||
type TInboxIssueDescription = {
|
type TInboxIssueDescription = {
|
||||||
|
containerClassName?: string;
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
@ -21,7 +22,7 @@ type TInboxIssueDescription = {
|
|||||||
|
|
||||||
// TODO: have to implement GPT Assistance
|
// TODO: have to implement GPT Assistance
|
||||||
export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props) => {
|
export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, workspaceId, data, handleData, editorRef } = props;
|
const {containerClassName, workspaceSlug, projectId, workspaceId, data, handleData, editorRef } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { loader } = useProjectInbox();
|
const { loader } = useProjectInbox();
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props
|
|||||||
dragDropEnabled={false}
|
dragDropEnabled={false}
|
||||||
onChange={(_description: object, description_html: string) => handleData("description_html", description_html)}
|
onChange={(_description: object, description_html: string) => handleData("description_html", description_html)}
|
||||||
placeholder={getDescriptionPlaceholder}
|
placeholder={getDescriptionPlaceholder}
|
||||||
|
containerClassName={containerClassName}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,326 +0,0 @@
|
|||||||
import { Fragment, useRef, useState } from "react";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import { Controller, useForm } from "react-hook-form";
|
|
||||||
import { Sparkle } from "lucide-react";
|
|
||||||
import { Transition, Dialog } from "@headlessui/react";
|
|
||||||
import { EditorRefApi } from "@plane/rich-text-editor";
|
|
||||||
// types
|
|
||||||
import { TIssue } from "@plane/types";
|
|
||||||
// ui
|
|
||||||
import { Button, Input, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui";
|
|
||||||
// components
|
|
||||||
import { GptAssistantPopover } from "@/components/core";
|
|
||||||
import { PriorityDropdown } from "@/components/dropdowns";
|
|
||||||
import { RichTextEditor } from "@/components/editor/rich-text-editor/rich-text-editor";
|
|
||||||
import { ISSUE_CREATED } from "@/constants/event-tracker";
|
|
||||||
import { useApplication, useEventTracker, useWorkspace, useProjectInbox } from "@/hooks/store";
|
|
||||||
// services
|
|
||||||
import { AIService } from "@/services/ai.service";
|
|
||||||
// components
|
|
||||||
// ui
|
|
||||||
// types
|
|
||||||
// constants
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
isOpen: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultValues: Partial<TIssue> = {
|
|
||||||
name: "",
|
|
||||||
description_html: "<p></p>",
|
|
||||||
priority: "none",
|
|
||||||
};
|
|
||||||
|
|
||||||
// services
|
|
||||||
const aiService = new AIService();
|
|
||||||
|
|
||||||
export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|
||||||
const { isOpen, onClose } = props;
|
|
||||||
// router
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
if (!workspaceSlug || !projectId) return null;
|
|
||||||
// states
|
|
||||||
const [createMore, setCreateMore] = useState(false);
|
|
||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
|
||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
|
||||||
// refs
|
|
||||||
const editorRef = useRef<EditorRefApi>(null);
|
|
||||||
// hooks
|
|
||||||
const workspaceStore = useWorkspace();
|
|
||||||
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug.toString() as string)?.id.toString() as string;
|
|
||||||
|
|
||||||
// store hooks
|
|
||||||
const { createInboxIssue } = useProjectInbox();
|
|
||||||
const {
|
|
||||||
config: { envConfig },
|
|
||||||
} = useApplication();
|
|
||||||
const { captureIssueEvent } = useEventTracker();
|
|
||||||
// form info
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
formState: { errors, isSubmitting },
|
|
||||||
handleSubmit,
|
|
||||||
reset,
|
|
||||||
watch,
|
|
||||||
getValues,
|
|
||||||
} = useForm<Partial<TIssue>>({ defaultValues });
|
|
||||||
const issueName = watch("name");
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
onClose();
|
|
||||||
reset(defaultValues);
|
|
||||||
editorRef?.current?.clearEditor();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFormSubmit = async (formData: Partial<TIssue>) => {
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
await createInboxIssue(workspaceSlug.toString(), projectId.toString(), formData)
|
|
||||||
.then((res) => {
|
|
||||||
if (!createMore) {
|
|
||||||
router.push(`/${workspaceSlug}/projects/${projectId}/inbox/?currentTab=open&inboxIssueId=${res?.issue?.id}`);
|
|
||||||
handleClose();
|
|
||||||
} else {
|
|
||||||
reset(defaultValues);
|
|
||||||
editorRef?.current?.clearEditor();
|
|
||||||
}
|
|
||||||
captureIssueEvent({
|
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: {
|
|
||||||
...formData,
|
|
||||||
state: "SUCCESS",
|
|
||||||
element: "Inbox page",
|
|
||||||
},
|
|
||||||
path: router.pathname,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
captureIssueEvent({
|
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: {
|
|
||||||
...formData,
|
|
||||||
state: "FAILED",
|
|
||||||
element: "Inbox page",
|
|
||||||
},
|
|
||||||
path: router.pathname,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAiAssistance = async (response: string) => {
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
editorRef.current?.setEditorValueAtCursorPosition(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAutoGenerateDescription = async () => {
|
|
||||||
const issueName = getValues("name");
|
|
||||||
if (!workspaceSlug || !projectId || !issueName) return;
|
|
||||||
|
|
||||||
setIAmFeelingLucky(true);
|
|
||||||
|
|
||||||
aiService
|
|
||||||
.createGptTask(workspaceSlug as string, projectId as string, {
|
|
||||||
prompt: issueName,
|
|
||||||
task: "Generate a proper description for this issue.",
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.response === "")
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Error!",
|
|
||||||
message:
|
|
||||||
"Issue title isn't informative enough to generate the description. Please try with a different title.",
|
|
||||||
});
|
|
||||||
else handleAiAssistance(res.response_html);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
const error = err?.data?.error;
|
|
||||||
|
|
||||||
if (err.status === 429)
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Error!",
|
|
||||||
message: error || "You have reached the maximum number of requests of 50 requests per month per user.",
|
|
||||||
});
|
|
||||||
else
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Error!",
|
|
||||||
message: error || "Some error occurred. Please try again.",
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.finally(() => setIAmFeelingLucky(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Transition.Root show={isOpen} as={Fragment}>
|
|
||||||
<Dialog as="div" className="relative z-20" onClose={onClose}>
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 bg-custom-backdrop transition-opacity" />
|
|
||||||
</Transition.Child>
|
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
|
||||||
<div className="my-10 flex items-center justify-center p-4 text-center sm:p-0 md:my-20">
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
>
|
|
||||||
<Dialog.Panel className="relative transform rounded-lg bg-custom-background-100 p-5 text-left shadow-custom-shadow-md transition-all sm:w-full sm:max-w-2xl">
|
|
||||||
<form onSubmit={handleSubmit(handleFormSubmit)}>
|
|
||||||
<div className="space-y-5">
|
|
||||||
<h3 className="text-xl font-semibold leading-6 text-custom-text-100">Create Inbox Issue</h3>
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div className="mt-2 space-y-3">
|
|
||||||
<div>
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="name"
|
|
||||||
rules={{
|
|
||||||
required: "Title is required",
|
|
||||||
maxLength: {
|
|
||||||
value: 255,
|
|
||||||
message: "Title should be less than 255 characters",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field: { value, onChange, ref } }) => (
|
|
||||||
<Input
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
type="text"
|
|
||||||
value={value}
|
|
||||||
onChange={onChange}
|
|
||||||
ref={ref}
|
|
||||||
hasError={Boolean(errors.name)}
|
|
||||||
placeholder="Title"
|
|
||||||
className="w-full resize-none text-xl"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="relative">
|
|
||||||
<div className="border-0.5 absolute bottom-3.5 right-3.5 z-10 flex rounded bg-custom-background-80">
|
|
||||||
{watch("name") && issueName !== "" && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-90 ${
|
|
||||||
iAmFeelingLucky ? "cursor-wait" : ""
|
|
||||||
}`}
|
|
||||||
onClick={handleAutoGenerateDescription}
|
|
||||||
disabled={iAmFeelingLucky}
|
|
||||||
>
|
|
||||||
{iAmFeelingLucky ? (
|
|
||||||
"Generating response..."
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Sparkle className="h-4 w-4" />I{"'"}m feeling lucky
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{envConfig?.has_openai_configured && (
|
|
||||||
<GptAssistantPopover
|
|
||||||
isOpen={gptAssistantModal}
|
|
||||||
projectId={projectId.toString()}
|
|
||||||
handleClose={() => {
|
|
||||||
setGptAssistantModal((prevData) => !prevData);
|
|
||||||
// this is done so that the title do not reset after gpt popover closed
|
|
||||||
reset(getValues());
|
|
||||||
}}
|
|
||||||
onResponse={(response) => {
|
|
||||||
handleAiAssistance(response);
|
|
||||||
}}
|
|
||||||
button={
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-90"
|
|
||||||
onClick={() => setGptAssistantModal((prevData) => !prevData)}
|
|
||||||
>
|
|
||||||
<Sparkle className="h-4 w-4" />
|
|
||||||
AI
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
className="!min-w-[38rem]"
|
|
||||||
placement="top-end"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Controller
|
|
||||||
name="description_html"
|
|
||||||
control={control}
|
|
||||||
render={({ field: { value, onChange } }) => (
|
|
||||||
<RichTextEditor
|
|
||||||
initialValue={!value || value === "" ? "<p></p>" : value}
|
|
||||||
ref={editorRef}
|
|
||||||
workspaceSlug={workspaceSlug.toString()}
|
|
||||||
workspaceId={workspaceId}
|
|
||||||
projectId={projectId.toString()}
|
|
||||||
dragDropEnabled={false}
|
|
||||||
onChange={(_description: object, description_html: string) => {
|
|
||||||
onChange(description_html);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="priority"
|
|
||||||
render={({ field: { value, onChange } }) => (
|
|
||||||
<div className="h-5">
|
|
||||||
<PriorityDropdown
|
|
||||||
value={value ?? "none"}
|
|
||||||
onChange={onChange}
|
|
||||||
buttonVariant="background-with-text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="-mx-5 mt-5 flex items-center justify-between gap-2 border-t border-custom-border-200 px-5 pt-5">
|
|
||||||
<div
|
|
||||||
className="flex cursor-pointer items-center gap-1"
|
|
||||||
onClick={() => setCreateMore((prevData) => !prevData)}
|
|
||||||
>
|
|
||||||
<span className="text-xs">Create more</span>
|
|
||||||
<ToggleSwitch value={createMore} onChange={() => {}} size="md" />
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button variant="neutral-primary" size="sm" onClick={() => handleClose()}>
|
|
||||||
Discard
|
|
||||||
</Button>
|
|
||||||
<Button variant="primary" size="sm" type="submit" loading={isSubmitting}>
|
|
||||||
{isSubmitting ? "Adding Issue..." : "Add Issue"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Dialog.Panel>
|
|
||||||
</Transition.Child>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
</Transition.Root>
|
|
||||||
);
|
|
||||||
});
|
|
@ -15,6 +15,7 @@ import { getDescriptionPlaceholder } from "@/helpers/issue.helper";
|
|||||||
import { useWorkspace } from "@/hooks/store";
|
import { useWorkspace } from "@/hooks/store";
|
||||||
|
|
||||||
export type IssueDescriptionInputProps = {
|
export type IssueDescriptionInputProps = {
|
||||||
|
containerClassName?: string;
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
issueId: string;
|
issueId: string;
|
||||||
@ -28,6 +29,7 @@ export type IssueDescriptionInputProps = {
|
|||||||
|
|
||||||
export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((props) => {
|
export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((props) => {
|
||||||
const {
|
const {
|
||||||
|
containerClassName,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
issueId,
|
issueId,
|
||||||
@ -110,11 +112,12 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
|
|||||||
placeholder={
|
placeholder={
|
||||||
placeholder ? placeholder : (isFocused, value) => getDescriptionPlaceholder(isFocused, value)
|
placeholder ? placeholder : (isFocused, value) => getDescriptionPlaceholder(isFocused, value)
|
||||||
}
|
}
|
||||||
|
containerClassName={containerClassName}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<RichTextReadOnlyEditor
|
<RichTextReadOnlyEditor
|
||||||
initialValue={localIssueDescription.description_html ?? ""}
|
initialValue={localIssueDescription.description_html ?? ""}
|
||||||
containerClassName="!p-0 !pt-2 text-custom-text-200 min-h-[150px]"
|
containerClassName={containerClassName}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="rounded-lg space-y-4">
|
<div className="rounded-lg space-y-4 pl-3">
|
||||||
{issue.parent_id && (
|
{issue.parent_id && (
|
||||||
<IssueParentDetail
|
<IssueParentDetail
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
@ -85,6 +85,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
issueOperations={issueOperations}
|
issueOperations={issueOperations}
|
||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
value={issue.name}
|
value={issue.name}
|
||||||
|
containerClassName="-ml-3"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* {issue?.description_html === issueDescription && ( */}
|
{/* {issue?.description_html === issueDescription && ( */}
|
||||||
@ -97,6 +98,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
issueOperations={issueOperations}
|
issueOperations={issueOperations}
|
||||||
setIsSubmitting={(value) => setIsSubmitting(value)}
|
setIsSubmitting={(value) => setIsSubmitting(value)}
|
||||||
|
containerClassName="-ml-3 border-none"
|
||||||
/>
|
/>
|
||||||
{/* )} */}
|
{/* )} */}
|
||||||
|
|
||||||
@ -121,14 +123,18 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<IssueAttachmentRoot
|
<div className="pl-3">
|
||||||
workspaceSlug={workspaceSlug}
|
<IssueAttachmentRoot
|
||||||
projectId={projectId}
|
workspaceSlug={workspaceSlug}
|
||||||
issueId={issueId}
|
projectId={projectId}
|
||||||
disabled={!isEditable}
|
issueId={issueId}
|
||||||
/>
|
disabled={!isEditable}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} disabled={isArchived} />
|
<div className="pl-3">
|
||||||
|
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} disabled={isArchived} />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -357,7 +357,7 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full w-full overflow-hidden">
|
<div className="flex h-full w-full overflow-hidden">
|
||||||
<div className="max-w-2/3 h-full w-full space-y-5 divide-y-2 divide-custom-border-200 overflow-y-auto p-5">
|
<div className="max-w-2/3 h-full w-full space-y-5 divide-y-2 divide-custom-border-200 overflow-y-auto px-6 py-5">
|
||||||
<IssueMainContent
|
<IssueMainContent
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
swrIssueDetails={swrIssueDetails}
|
swrIssueDetails={swrIssueDetails}
|
||||||
|
@ -480,6 +480,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
tabIndex={getTabIndex("description_html")}
|
tabIndex={getTabIndex("description_html")}
|
||||||
placeholder={getDescriptionPlaceholder}
|
placeholder={getDescriptionPlaceholder}
|
||||||
|
containerClassName="border-[0.5px] border-custom-border-200 py-3"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -69,6 +69,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = observer(
|
|||||||
issueOperations={issueOperations}
|
issueOperations={issueOperations}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={issue.name}
|
value={issue.name}
|
||||||
|
containerClassName="-ml-3"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IssueDescriptionInput
|
<IssueDescriptionInput
|
||||||
@ -81,6 +82,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = observer(
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
issueOperations={issueOperations}
|
issueOperations={issueOperations}
|
||||||
setIsSubmitting={(value) => setIsSubmitting(value)}
|
setIsSubmitting={(value) => setIsSubmitting(value)}
|
||||||
|
containerClassName="-ml-3 border-none"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{currentUser && (
|
{currentUser && (
|
||||||
|
@ -3,6 +3,7 @@ import { observer } from "mobx-react";
|
|||||||
// components
|
// components
|
||||||
import { TextArea } from "@plane/ui";
|
import { TextArea } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
|
import { cn } from "@/helpers/common.helper";
|
||||||
import useDebounce from "@/hooks/use-debounce";
|
import useDebounce from "@/hooks/use-debounce";
|
||||||
import { TIssueOperations } from "./issue-detail";
|
import { TIssueOperations } from "./issue-detail";
|
||||||
// hooks
|
// hooks
|
||||||
@ -16,12 +17,26 @@ export type IssueTitleInputProps = {
|
|||||||
issueOperations: TIssueOperations;
|
issueOperations: TIssueOperations;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
issueId: string;
|
issueId: string;
|
||||||
|
className?: string;
|
||||||
|
containerClassName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IssueTitleInput: FC<IssueTitleInputProps> = observer((props) => {
|
export const IssueTitleInput: FC<IssueTitleInputProps> = observer((props) => {
|
||||||
const { disabled, value, workspaceSlug, isSubmitting, setIsSubmitting, issueId, issueOperations, projectId } = props;
|
const {
|
||||||
|
disabled,
|
||||||
|
value,
|
||||||
|
workspaceSlug,
|
||||||
|
isSubmitting,
|
||||||
|
setIsSubmitting,
|
||||||
|
issueId,
|
||||||
|
issueOperations,
|
||||||
|
projectId,
|
||||||
|
className,
|
||||||
|
containerClassName,
|
||||||
|
} = props;
|
||||||
// states
|
// states
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
|
const [isLengthVisible, setIsLengthVisible] = useState(false);
|
||||||
// hooks
|
// hooks
|
||||||
const debouncedValue = useDebounce(title, 1500);
|
const debouncedValue = useDebounce(title, 1500);
|
||||||
|
|
||||||
@ -76,19 +91,32 @@ export const IssueTitleInput: FC<IssueTitleInputProps> = observer((props) => {
|
|||||||
if (disabled) return <div className="text-2xl font-medium">{title}</div>;
|
if (disabled) return <div className="text-2xl font-medium">{title}</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className={cn("relative", containerClassName)}>
|
||||||
<TextArea
|
<TextArea
|
||||||
id="title-input"
|
id="title-input"
|
||||||
className={`min-h-min block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-2xl font-medium outline-none ring-0 focus:ring-1 focus:ring-custom-primary ${
|
className={cn(
|
||||||
title?.length === 0 ? "!ring-red-400" : ""
|
"block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-0 text-2xl font-medium outline-none ring-0",
|
||||||
}`}
|
{
|
||||||
|
"ring-red-400": title.length === 0,
|
||||||
|
},
|
||||||
|
className
|
||||||
|
)}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={title}
|
value={title}
|
||||||
onChange={handleTitleChange}
|
onChange={handleTitleChange}
|
||||||
maxLength={255}
|
maxLength={255}
|
||||||
placeholder="Issue title"
|
placeholder="Issue title"
|
||||||
|
onFocus={() => setIsLengthVisible(true)}
|
||||||
|
onBlur={() => setIsLengthVisible(false)}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute bottom-1 right-1 z-[2] rounded bg-custom-background-100 p-0.5 text-xs text-custom-text-200">
|
<div
|
||||||
|
className={cn(
|
||||||
|
"pointer-events-none absolute bottom-1 right-1 z-[2] rounded bg-custom-background-100 p-0.5 text-xs text-custom-text-200 opacity-0 transition-opacity",
|
||||||
|
{
|
||||||
|
"opacity-100": isLengthVisible,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
<span className={`${title.length === 0 || title.length > 255 ? "text-red-500" : ""}`}>{title.length}</span>
|
<span className={`${title.length === 0 || title.length > 255 ? "text-red-500" : ""}`}>{title.length}</span>
|
||||||
/255
|
/255
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,8 +91,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
|||||||
<div
|
<div
|
||||||
className={cn("sticky top-0 hidden h-full flex-shrink-0 -translate-x-full p-5 duration-200 md:block", {
|
className={cn("sticky top-0 hidden h-full flex-shrink-0 -translate-x-full p-5 duration-200 md:block", {
|
||||||
"translate-x-0": sidePeekVisible,
|
"translate-x-0": sidePeekVisible,
|
||||||
"w-56 lg:w-72": !isFullWidth,
|
"w-40 lg:w-56": !isFullWidth,
|
||||||
"w-[10%]": isFullWidth,
|
"w-[5%]": isFullWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{!isFullWidth && (
|
{!isFullWidth && (
|
||||||
@ -104,8 +104,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cn("h-full w-full pt-5", {
|
className={cn("h-full w-full pt-5", {
|
||||||
"md:w-[calc(100%-14rem)] xl:w-[calc(100%-18rem-18rem)]": !isFullWidth,
|
"md:w-[calc(100%-10rem)] xl:w-[calc(100%-14rem-14rem)]": !isFullWidth,
|
||||||
"md:w-[80%]": isFullWidth,
|
"md:w-[90%]": isFullWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="h-full w-full flex flex-col gap-y-7 overflow-y-auto overflow-x-hidden">
|
<div className="h-full w-full flex flex-col gap-y-7 overflow-y-auto overflow-x-hidden">
|
||||||
@ -164,8 +164,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cn("hidden xl:block flex-shrink-0", {
|
className={cn("hidden xl:block flex-shrink-0", {
|
||||||
"w-56 lg:w-72": !isFullWidth,
|
"w-40 lg:w-56": !isFullWidth,
|
||||||
"w-[10%]": isFullWidth,
|
"w-[5%]": isFullWidth,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,8 +46,8 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
|
|||||||
<div className="hidden md:flex items-center border-b border-custom-border-200 px-3 py-2 md:px-5">
|
<div className="hidden md:flex items-center border-b border-custom-border-200 px-3 py-2 md:px-5">
|
||||||
<div
|
<div
|
||||||
className={cn("flex-shrink-0", {
|
className={cn("flex-shrink-0", {
|
||||||
"w-56 lg:w-72": !isFullWidth,
|
"w-40 lg:w-56": !isFullWidth,
|
||||||
"w-[10%]": isFullWidth,
|
"w-[5%]": isFullWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<PageSummaryPopover
|
<PageSummaryPopover
|
||||||
|
@ -23,7 +23,7 @@ export const PageEditorTitle: React.FC<Props> = observer((props) => {
|
|||||||
<>
|
<>
|
||||||
{readOnly ? (
|
{readOnly ? (
|
||||||
<h6
|
<h6
|
||||||
className="break-words bg-transparent text-4xl font-bold"
|
className="break-words bg-transparent text-[1.75rem] font-semibold"
|
||||||
style={{
|
style={{
|
||||||
lineHeight: "1.2",
|
lineHeight: "1.2",
|
||||||
}}
|
}}
|
||||||
@ -34,7 +34,7 @@ export const PageEditorTitle: React.FC<Props> = observer((props) => {
|
|||||||
<>
|
<>
|
||||||
<TextArea
|
<TextArea
|
||||||
onChange={(e) => updateTitle(e.target.value)}
|
onChange={(e) => updateTitle(e.target.value)}
|
||||||
className="w-full bg-custom-background text-4xl font-bold outline-none p-0 border-none resize-none rounded-none"
|
className="w-full bg-custom-background text-[1.75rem] font-semibold outline-none p-0 border-none resize-none rounded-none"
|
||||||
style={{
|
style={{
|
||||||
lineHeight: "1.2",
|
lineHeight: "1.2",
|
||||||
}}
|
}}
|
||||||
|
@ -103,9 +103,9 @@ const ArchivedIssueDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
</Loader>
|
</Loader>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full overflow-hidden">
|
<div className="flex h-full overflow-hidden">
|
||||||
<div className="h-full w-full space-y-3 divide-y-2 divide-custom-border-200 overflow-y-auto p-5">
|
<div className="h-full w-full space-y-3 divide-y-2 divide-custom-border-200 overflow-y-auto">
|
||||||
{issue?.archived_at && canRestoreIssue && (
|
{issue?.archived_at && canRestoreIssue && (
|
||||||
<div className="flex items-center justify-between gap-2 rounded-md border border-custom-border-200 bg-custom-background-90 px-2.5 py-2 text-sm text-custom-text-200">
|
<div className="flex items-center justify-between gap-2 rounded-md border border-custom-border-200 bg-custom-background-90 px-2.5 py-2 text-sm text-custom-text-200 my-5 mx-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ArchiveIcon className="h-4 w-4" />
|
<ArchiveIcon className="h-4 w-4" />
|
||||||
<p>This issue has been archived.</p>
|
<p>This issue has been archived.</p>
|
||||||
|
Loading…
Reference in New Issue
Block a user