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