mirror of
https://github.com/linsa-io/linsa.git
synced 2026-01-12 12:20:23 +01:00
link title editing
This commit is contained in:
@@ -121,22 +121,24 @@ interface LinkFormProps extends React.ComponentPropsWithoutRef<"form"> {
|
||||
}
|
||||
|
||||
const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess, onCancel, personalLink }, ref) => {
|
||||
const selectedLink = useCoState(PersonalLink, personalLink?.id)
|
||||
const [isFetching, setIsFetching] = useState(false)
|
||||
const { me } = useAccount()
|
||||
const form = useForm<LinkFormValues>({
|
||||
resolver: zodResolver(createLinkSchema),
|
||||
defaultValues: DEFAULT_FORM_VALUES
|
||||
defaultValues: {
|
||||
...DEFAULT_FORM_VALUES,
|
||||
isLink: true
|
||||
}
|
||||
})
|
||||
|
||||
const selectedLink = useCoState(PersonalLink, personalLink?.id)
|
||||
const title = form.watch("title")
|
||||
const [inputValue, setInputValue] = useState("")
|
||||
const [originalLink, setOriginalLink] = useState<string>("")
|
||||
const [linkValidation, setLinkValidation] = useState<string | null>(null)
|
||||
const [invalidLink, setInvalidLink] = useState(false)
|
||||
const [showLinkStatus, setShowLinkStatus] = useState(false)
|
||||
const [showLink, setShowLink] = useState(false)
|
||||
const [debouncedText, setDebouncedText] = useState<string>("")
|
||||
useDebounce(() => setDebouncedText(title), 300, [title])
|
||||
|
||||
const [showStatusOptions, setShowStatusOptions] = useState(false)
|
||||
const [selectedStatus, setSelectedStatus] = useState<string | null>(null)
|
||||
|
||||
@@ -171,21 +173,23 @@ const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess,
|
||||
const changeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
setInputValue(value)
|
||||
setShowLinkStatus(false)
|
||||
setInvalidLink(false)
|
||||
form.setValue("title", value)
|
||||
}
|
||||
|
||||
const pressEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
if (e.key === "Enter" && !showLink) {
|
||||
e.preventDefault()
|
||||
const trimmedValue = inputValue.trim().toLowerCase()
|
||||
if (LibIsUrl(trimmedValue)) {
|
||||
form.setValue("title", trimmedValue)
|
||||
setShowLinkStatus(true)
|
||||
setShowLink(true)
|
||||
setInvalidLink(false)
|
||||
setLinkValidation(trimmedValue)
|
||||
setInputValue(trimmedValue)
|
||||
form.setValue("title", trimmedValue)
|
||||
} else {
|
||||
setInvalidLink(true)
|
||||
setShowLinkStatus(true)
|
||||
setShowLink(true)
|
||||
setLinkValidation(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,10 +216,10 @@ const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess,
|
||||
setIsFetching(false)
|
||||
}
|
||||
}
|
||||
if (showLinkStatus && !invalidLink && LibIsUrl(form.getValues("title").toLowerCase())) {
|
||||
if (showLink && !invalidLink && LibIsUrl(form.getValues("title").toLowerCase())) {
|
||||
fetchMetadata(ensureUrlProtocol(form.getValues("title").toLowerCase()))
|
||||
}
|
||||
}, [showLinkStatus, invalidLink, form])
|
||||
}, [showLink, invalidLink, form])
|
||||
|
||||
const onSubmit = (values: LinkFormValues) => {
|
||||
if (isFetching) return
|
||||
@@ -279,7 +283,7 @@ const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess,
|
||||
<div className="flex flex-auto flex-col gap-1.5">
|
||||
<div className="flex flex-row items-start justify-between">
|
||||
<div className="flex grow flex-row items-center gap-1.5">
|
||||
<Button
|
||||
{/* <Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
@@ -297,7 +301,7 @@ const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess,
|
||||
) : (
|
||||
<BoxIcon size={16} />
|
||||
)}
|
||||
</Button>
|
||||
</Button> */}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -324,9 +328,9 @@ const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess,
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{showLinkStatus && (
|
||||
{showLink && (
|
||||
<span className={cn("mr-5 max-w-[200px] truncate text-xs", invalidLink ? "text-red-500" : "")}>
|
||||
{invalidLink ? "Allowing links only" : originalLink || ""}
|
||||
{invalidLink ? "Only links are allowed" : linkValidation || originalLink || ""}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -423,7 +427,7 @@ const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess,
|
||||
<Button size="sm" type="button" variant="ghost" onClick={undoEditing}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button size="sm" disabled={isFetching}>
|
||||
<Button size="sm" type="submit" disabled={isFetching}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { z } from "zod"
|
||||
import { isUrl } from "@/lib/utils"
|
||||
|
||||
export const createLinkSchema = z.object({
|
||||
title: z
|
||||
.string({
|
||||
message: "Please enter a valid title"
|
||||
})
|
||||
.min(1, {
|
||||
message: "Please enter a valid title"
|
||||
}),
|
||||
title: z.string().min(1, { message: "Title can't be empty" }),
|
||||
originalUrl: z.string().refine(isUrl, { message: "Only links are allowed" }),
|
||||
description: z.string().optional(),
|
||||
topic: z.string().optional(),
|
||||
isLink: z.boolean().default(false),
|
||||
isLink: z.boolean().default(true),
|
||||
meta: z
|
||||
.object({
|
||||
url: z.string(),
|
||||
|
||||
@@ -17,7 +17,7 @@ export class LinkMetadata extends CoMap {
|
||||
export class PersonalLink extends CoMap {
|
||||
title = co.string
|
||||
slug = co.string
|
||||
description = nullable(co.string)
|
||||
description = co.optional.string
|
||||
completed = co.boolean
|
||||
sequence = co.number
|
||||
isLink = co.boolean
|
||||
|
||||
Reference in New Issue
Block a user