落地 synastry/star/ask API 与 H5 页面,补齐 cece-frontend-re complete-design 证据文档,并加入 Android 模拟器截图抓取脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
/** Build / parse client-side share landing query (no server). */
|
|
|
|
export type PortraitSharePayload = {
|
|
type: 'portrait'
|
|
title: string
|
|
line: string
|
|
keywords: string[]
|
|
}
|
|
|
|
export type RelationSharePayload = {
|
|
type: 'relation'
|
|
me: string
|
|
other: string
|
|
diff: string
|
|
keywords: string[]
|
|
}
|
|
|
|
export type SharePayload = PortraitSharePayload | RelationSharePayload
|
|
|
|
export function buildSharePath(payload: SharePayload): string {
|
|
const q = new URLSearchParams()
|
|
q.set('type', payload.type)
|
|
if (payload.type === 'portrait') {
|
|
if (payload.title) q.set('t', payload.title)
|
|
if (payload.line) q.set('l', payload.line)
|
|
if (payload.keywords.length) q.set('k', payload.keywords.slice(0, 6).join(','))
|
|
} else {
|
|
if (payload.me) q.set('me', payload.me)
|
|
if (payload.other) q.set('ot', payload.other)
|
|
if (payload.diff) q.set('d', payload.diff)
|
|
if (payload.keywords.length) q.set('k', payload.keywords.slice(0, 6).join(','))
|
|
}
|
|
return `/share?${q.toString()}`
|
|
}
|
|
|
|
export function parseShareQuery(query: Record<string, unknown>): SharePayload | null {
|
|
const type = String(query.type || '')
|
|
const keywords = String(query.k || '')
|
|
.split(',')
|
|
.map((s) => s.trim())
|
|
.filter(Boolean)
|
|
if (type === 'portrait') {
|
|
const title = String(query.t || '')
|
|
const line = String(query.l || '')
|
|
if (!title && !line && !keywords.length) return null
|
|
return { type: 'portrait', title, line, keywords }
|
|
}
|
|
if (type === 'relation') {
|
|
const me = String(query.me || '')
|
|
const other = String(query.ot || '')
|
|
const diff = String(query.d || '')
|
|
if (!me && !other && !diff) return null
|
|
return { type: 'relation', me, other, diff, keywords }
|
|
}
|
|
return null
|
|
}
|
|
|
|
export async function copyText(text: string): Promise<boolean> {
|
|
try {
|
|
if (navigator.clipboard?.writeText) {
|
|
await navigator.clipboard.writeText(text)
|
|
return true
|
|
}
|
|
} catch {
|
|
/* fall through */
|
|
}
|
|
try {
|
|
const ta = document.createElement('textarea')
|
|
ta.value = text
|
|
ta.style.position = 'fixed'
|
|
ta.style.left = '-9999px'
|
|
document.body.appendChild(ta)
|
|
ta.select()
|
|
const ok = document.execCommand('copy')
|
|
document.body.removeChild(ta)
|
|
return ok
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|