feat(link): enhance LinkEditForm with advanced Open Graph fields toggle

- Added a toggle for advanced settings in the LinkEditForm to show/hide Open Graph fields (ogTitle, ogDescription, ogImageUrl).
- Updated the form to initialize these fields with default values if available.
- Introduced a new label for the advanced section in the messages file.

This enhancement improves user experience by allowing users to manage Open Graph metadata more efficiently.
This commit is contained in:
crbon 2026-01-21 17:25:29 +10:00
parent e295fca187
commit 2c91d4e68d
2 changed files with 59 additions and 21 deletions

View file

@ -13,7 +13,7 @@ import {
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useConfig, useLinkQuery, useMessages } from '@/components/hooks'; import { useConfig, useLinkQuery, useMessages } from '@/components/hooks';
import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery'; import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery';
import { RefreshCw } from '@/components/icons'; import { ChevronDown, ChevronRight, RefreshCw } from '@/components/icons';
import { LINKS_URL } from '@/lib/constants'; import { LINKS_URL } from '@/lib/constants';
import { getRandomChars } from '@/lib/generate'; import { getRandomChars } from '@/lib/generate';
import { isValidUrl } from '@/lib/url'; import { isValidUrl } from '@/lib/url';
@ -43,6 +43,7 @@ export function LinkEditForm({
const hostUrl = linksUrl || LINKS_URL; const hostUrl = linksUrl || LINKS_URL;
const { data, isLoading } = useLinkQuery(linkId); const { data, isLoading } = useLinkQuery(linkId);
const [slug, setSlug] = useState(generateId()); const [slug, setSlug] = useState(generateId());
const [showAdvanced, setShowAdvanced] = useState(false);
const handleSubmit = async (data: any) => { const handleSubmit = async (data: any) => {
await mutateAsync(data, { await mutateAsync(data, {
@ -81,7 +82,17 @@ export function LinkEditForm({
} }
return ( return (
<Form onSubmit={handleSubmit} error={getErrorMessage(error)} defaultValues={{ slug, ...data }}> <Form
onSubmit={handleSubmit}
error={getErrorMessage(error)}
defaultValues={{
slug,
...data,
ogTitle: data?.ogTitle || '',
ogDescription: data?.ogDescription || '',
ogImageUrl: data?.ogImageUrl || '',
}}
>
{({ setValue }) => { {({ setValue }) => {
return ( return (
<> <>
@ -101,28 +112,16 @@ export function LinkEditForm({
<TextField placeholder="https://example.com" autoComplete="off" /> <TextField placeholder="https://example.com" autoComplete="off" />
</FormField> </FormField>
<FormField label="Title" name="ogTitle">
<TextField autoComplete="off" />
</FormField>
<FormField label="Description" name="ogDescription">
<TextField autoComplete="off" />
</FormField>
<FormField label="Image URL" name="ogImageUrl">
<TextField autoComplete="off" />
</FormField>
<Column> <Column>
<Label>{formatMessage(labels.link)}</Label> <Label>{formatMessage(labels.link)}</Label>
<Row alignItems="center" gap> <Row alignItems="center" gap>
<FormField <TextField
name="slug" value={`${hostUrl}/${slug}`}
rules={{ required: formatMessage(labels.required) }} autoComplete="off"
style={{ width: '100%' }} isReadOnly
> allowCopy
<TextField autoComplete="off" /> style={{ flex: 1 }}
</FormField> />
<Button <Button
variant="quiet" variant="quiet"
onPress={() => setValue('slug', handleSlug(), { shouldDirty: true })} onPress={() => setValue('slug', handleSlug(), { shouldDirty: true })}
@ -134,6 +133,44 @@ export function LinkEditForm({
</Row> </Row>
</Column> </Column>
<Row
alignItems="center"
gap="2"
style={{ cursor: 'pointer', userSelect: 'none' }}
onClick={() => setShowAdvanced(!showAdvanced)}
>
<Icon size="sm">{showAdvanced ? <ChevronDown /> : <ChevronRight />}</Icon>
<Label style={{ cursor: 'pointer' }}>{formatMessage(labels.advanced)}</Label>
</Row>
{showAdvanced && (
<Column gap="3">
<FormField label="Title" name="ogTitle">
<TextField autoComplete="off" />
</FormField>
<FormField label="Description" name="ogDescription">
<TextField autoComplete="off" />
</FormField>
<FormField label="Image URL" name="ogImageUrl">
<TextField autoComplete="off" />
</FormField>
<Column>
<Label>{formatMessage(labels.path)}</Label>
<TextField
value={slug}
onChange={(value: string) => {
setSlug(value);
setValue('slug', value, { shouldDirty: true });
}}
autoComplete="off"
/>
</Column>
</Column>
)}
<Row justifyContent="flex-end" paddingTop="3" gap="3"> <Row justifyContent="flex-end" paddingTop="3" gap="3">
{onClose && ( {onClose && (
<Button isDisabled={isPending} onPress={onClose}> <Button isDisabled={isPending} onPress={onClose}>

View file

@ -363,6 +363,7 @@ export const labels = defineMessages({
support: { id: 'label.support', defaultMessage: 'Support' }, support: { id: 'label.support', defaultMessage: 'Support' },
documentation: { id: 'label.documentation', defaultMessage: 'Documentation' }, documentation: { id: 'label.documentation', defaultMessage: 'Documentation' },
switchAccount: { id: 'label.switch-account', defaultMessage: 'Switch account' }, switchAccount: { id: 'label.switch-account', defaultMessage: 'Switch account' },
advanced: { id: 'label.advanced', defaultMessage: 'Advanced' },
}); });
export const messages = defineMessages({ export const messages = defineMessages({