feat: add option to add client tag

This commit is contained in:
codytseng
2024-12-24 12:13:39 +08:00
parent 234319ef50
commit 31f70c2ab1
8 changed files with 117 additions and 12 deletions

23
package-lock.json generated
View File

@@ -15,6 +15,7 @@
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-hover-card": "^1.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-scroll-area": "1.2.0",
"@radix-ui/react-separator": "^1.1.1",
@@ -2832,6 +2833,28 @@
}
}
},
"node_modules/@radix-ui/react-label": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.1.tgz",
"integrity": "sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==",
"dependencies": {
"@radix-ui/react-primitive": "2.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-menu": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.4.tgz",

View File

@@ -25,6 +25,7 @@
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-hover-card": "^1.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-scroll-area": "1.2.0",
"@radix-ui/react-separator": "^1.1.1",

View File

@@ -6,20 +6,23 @@ import {
DialogHeader,
DialogTitle
} from '@/components/ui/dialog'
import { Label } from '@/components/ui/label'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Switch } from '@/components/ui/switch'
import { Textarea } from '@/components/ui/textarea'
import { StorageKey } from '@/constants'
import { useToast } from '@/hooks/use-toast'
import { createShortTextNoteDraftEvent } from '@/lib/draft-event'
import { useNostr } from '@/providers/NostrProvider'
import client from '@/services/client.service'
import { LoaderCircle } from 'lucide-react'
import { ChevronDown, LoaderCircle } from 'lucide-react'
import { Event } from 'nostr-tools'
import { Dispatch, useState } from 'react'
import { Dispatch, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import UserAvatar from '../UserAvatar'
import Mentions from './Metions'
import Preview from './Preview'
import Uploader from './Uploader'
import { useTranslation } from 'react-i18next'
export default function PostDialog({
defaultContent = '',
@@ -37,8 +40,14 @@ export default function PostDialog({
const { publish, checkLogin } = useNostr()
const [content, setContent] = useState(defaultContent)
const [posting, setPosting] = useState(false)
const [showMoreOptions, setShowMoreOptions] = useState(false)
const [addClientTag, setAddClientTag] = useState(false)
const canPost = !!content && !posting
useEffect(() => {
setAddClientTag(window.localStorage.getItem(StorageKey.ADD_CLIENT_TAG) === 'true')
}, [])
const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setContent(e.target.value)
}
@@ -58,7 +67,10 @@ export default function PostDialog({
const relayList = await client.fetchRelayList(parentEvent.pubkey)
additionalRelayUrls.push(...relayList.read.slice(0, 5))
}
const draftEvent = await createShortTextNoteDraftEvent(content, parentEvent)
const draftEvent = await createShortTextNoteDraftEvent(content, {
parentEvent,
addClientTag
})
await publish(draftEvent, additionalRelayUrls)
setContent('')
setOpen(false)
@@ -90,6 +102,11 @@ export default function PostDialog({
})
}
const onAddClientTagChange = (checked: boolean) => {
setAddClientTag(checked)
window.localStorage.setItem(StorageKey.ADD_CLIENT_TAG, checked.toString())
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="p-0" withoutClose>
@@ -117,8 +134,20 @@ export default function PostDialog({
/>
{content && <Preview content={content} />}
<div className="flex items-center justify-between">
<div className="flex gap-2 items-center">
<Uploader setContent={setContent} />
<div className="flex gap-2">
<Button
variant="link"
className="text-foreground gap-0 px-0"
onClick={() => setShowMoreOptions((pre) => !pre)}
>
{t('More options')}
<ChevronDown
className={`transition-transform ${showMoreOptions ? 'rotate-180' : ''}`}
/>
</Button>
</div>
<div className="flex gap-2 items-center">
<Mentions content={content} parentEvent={parentEvent} />
<Button
variant="secondary"
@@ -135,6 +164,21 @@ export default function PostDialog({
</Button>
</div>
</div>
{showMoreOptions && (
<div className="space-y-2">
<div className="flex items-center space-x-2">
<Label htmlFor="add-client-tag">{t('Add client tag')}</Label>
<Switch
id="add-client-tag"
checked={addClientTag}
onCheckedChange={onAddClientTagChange}
/>
</div>
<div className="text-muted-foreground text-xs">
{t('Show others this was sent via Jumble')}
</div>
</div>
)}
</div>
</ScrollArea>
</DialogContent>

View File

@@ -0,0 +1,24 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
export { Label }

View File

@@ -2,7 +2,8 @@ export const StorageKey = {
THEME_SETTING: 'themeSetting',
RELAY_GROUPS: 'relayGroups',
ACCOUNTS: 'accounts',
CURRENT_ACCOUNT: 'currentAccount'
CURRENT_ACCOUNT: 'currentAccount',
ADD_CLIENT_TAG: 'addClientTag'
}
export const BIG_RELAY_URLS = [

View File

@@ -87,6 +87,9 @@ export default {
'reload notes': 'reload notes',
'Logged in Accounts': 'Logged in Accounts',
'Add an Account': 'Add an Account',
Accounts: 'Accounts'
Accounts: 'Accounts',
'More options': 'More options',
'Add client tag': 'Add client tag',
'Show others this was sent via Jumble': 'Show others this was sent via Jumble'
}
}

View File

@@ -86,6 +86,9 @@ export default {
'reload notes': '重新加载笔记',
'Logged in Accounts': '已登录账户',
'Add an Account': '添加账户',
Accounts: '多帐户'
Accounts: '多帐户',
'More options': '更多选项',
'Add client tag': '添加客户端标签',
'Show others this was sent via Jumble': '告诉别人这是通过 Jumble 发送的'
}
}

View File

@@ -39,10 +39,13 @@ export function createRepostDraftEvent(event: Event): TDraftEvent {
export async function createShortTextNoteDraftEvent(
content: string,
options: {
parentEvent?: Event
addClientTag?: boolean
} = {}
): Promise<TDraftEvent> {
const { pubkeys, otherRelatedEventIds, quoteEventIds, rootEventId, parentEventId } =
await extractMentions(content, parentEvent)
await extractMentions(content, options.parentEvent)
const hashtags = extractHashtags(content)
const tags = pubkeys
@@ -50,7 +53,6 @@ export async function createShortTextNoteDraftEvent(
.concat(otherRelatedEventIds.map((eventId) => ['e', eventId]))
.concat(quoteEventIds.map((eventId) => ['q', eventId]))
.concat(hashtags.map((hashtag) => ['t', hashtag]))
.concat([['client', 'jumble']])
if (rootEventId) {
tags.push(['e', rootEventId, '', 'root'])
@@ -60,6 +62,10 @@ export async function createShortTextNoteDraftEvent(
tags.push(['e', parentEventId, '', 'reply'])
}
if (options.addClientTag) {
tags.push(['client', 'jumble'])
}
return {
kind: kinds.ShortTextNote,
content,