Merge branch 'app-2066' into app-2067
# Conflicts: # src/state/queries/klipy.ts
This commit is contained in:
@@ -186,7 +186,7 @@ function LandingPage() {
|
||||
function Skeleton() {
|
||||
return (
|
||||
<Container>
|
||||
<div className="flex-1 flex-col flex gap-2 pb-8">
|
||||
<div className="flex-1 flex-col flex gap-2 p-5 pb-8">
|
||||
<div className="flex gap-2.5 items-center">
|
||||
<div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-100 dark:bg-slate-700 shrink-0 animate-pulse" />
|
||||
<div className="flex-1">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, viewport-fit=cover">
|
||||
<meta name="referrer" content="origin-when-cross-origin">
|
||||
<!--
|
||||
Preconnect to essential domains
|
||||
|
||||
@@ -109,7 +109,7 @@ function EmbedDialogInner({
|
||||
<Trans>Embed post</Trans>
|
||||
</Text>
|
||||
<Text
|
||||
style={[a.text_md, t.atoms.text_contrast_medium, a.leading_normal]}>
|
||||
style={[a.text_md, t.atoms.text_contrast_medium, a.leading_snug]}>
|
||||
<Trans>
|
||||
Embed this post in your website. Simply copy the following snippet
|
||||
and paste it into the HTML code of your website.
|
||||
@@ -117,12 +117,7 @@ function EmbedDialogInner({
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
a.border,
|
||||
t.atoms.border_contrast_low,
|
||||
a.rounded_sm,
|
||||
a.overflow_hidden,
|
||||
]}>
|
||||
style={[a.border, t.atoms.border_contrast_low, {borderRadius: 18}]}>
|
||||
<Button
|
||||
label={
|
||||
showCustomisation
|
||||
@@ -190,10 +185,9 @@ function EmbedDialogInner({
|
||||
<Button
|
||||
label={_(msg`Copy code`)}
|
||||
color="primary"
|
||||
variant="solid"
|
||||
size="large"
|
||||
onPress={() => {
|
||||
navigator.clipboard.writeText(snippet)
|
||||
void navigator.clipboard.writeText(snippet)
|
||||
setCopied(true)
|
||||
}}>
|
||||
{copied ? (
|
||||
|
||||
@@ -2399,12 +2399,12 @@ msgstr ""
|
||||
msgid "Collapses list of users for a given notification"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:155
|
||||
#: src/components/dialogs/Embed.tsx:150
|
||||
#: src/screens/Settings/AppearanceSettings.tsx:81
|
||||
msgid "Color mode"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:152
|
||||
#: src/components/dialogs/Embed.tsx:147
|
||||
msgid "Color theme"
|
||||
msgstr ""
|
||||
|
||||
@@ -2646,7 +2646,7 @@ msgstr ""
|
||||
msgid "Copied to clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:203
|
||||
#: src/components/dialogs/Embed.tsx:197
|
||||
#: src/screens/Settings/components/CopyButton.tsx:66
|
||||
msgid "Copied!"
|
||||
msgstr ""
|
||||
@@ -2673,8 +2673,8 @@ msgstr ""
|
||||
msgid "Copy author DID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:191
|
||||
#: src/components/dialogs/Embed.tsx:208
|
||||
#: src/components/dialogs/Embed.tsx:186
|
||||
#: src/components/dialogs/Embed.tsx:202
|
||||
msgid "Copy code"
|
||||
msgstr ""
|
||||
|
||||
@@ -2948,7 +2948,7 @@ msgstr ""
|
||||
msgid "Custom"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:145
|
||||
#: src/components/dialogs/Embed.tsx:140
|
||||
msgid "Customization options"
|
||||
msgstr ""
|
||||
|
||||
@@ -2964,8 +2964,8 @@ msgstr ""
|
||||
msgid "Dangerous substances or drug abuse"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:169
|
||||
#: src/components/dialogs/Embed.tsx:171
|
||||
#: src/components/dialogs/Embed.tsx:164
|
||||
#: src/components/dialogs/Embed.tsx:166
|
||||
#: src/screens/Settings/AppearanceSettings.tsx:93
|
||||
#: src/screens/Settings/AppearanceSettings.tsx:114
|
||||
msgid "Dark"
|
||||
@@ -3613,7 +3613,7 @@ msgstr ""
|
||||
msgid "Email Verified"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:183
|
||||
#: src/components/dialogs/Embed.tsx:178
|
||||
msgid "Embed HTML code"
|
||||
msgstr ""
|
||||
|
||||
@@ -5004,7 +5004,7 @@ msgstr ""
|
||||
msgid "Hide all events"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:129
|
||||
#: src/components/dialogs/Embed.tsx:124
|
||||
msgid "Hide customization options"
|
||||
msgstr ""
|
||||
|
||||
@@ -5701,8 +5701,8 @@ msgstr ""
|
||||
msgid "Let's go!"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:164
|
||||
#: src/components/dialogs/Embed.tsx:166
|
||||
#: src/components/dialogs/Embed.tsx:159
|
||||
#: src/components/dialogs/Embed.tsx:161
|
||||
#: src/screens/Settings/AppearanceSettings.tsx:89
|
||||
msgid "Light"
|
||||
msgstr ""
|
||||
@@ -9359,7 +9359,7 @@ msgstr ""
|
||||
msgid "Show badge and filter from feeds"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:130
|
||||
#: src/components/dialogs/Embed.tsx:125
|
||||
msgid "Show customization options"
|
||||
msgstr ""
|
||||
|
||||
@@ -9910,8 +9910,8 @@ msgstr ""
|
||||
msgid "Switch to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/Embed.tsx:159
|
||||
#: src/components/dialogs/Embed.tsx:161
|
||||
#: src/components/dialogs/Embed.tsx:154
|
||||
#: src/components/dialogs/Embed.tsx:156
|
||||
#: src/screens/Settings/AppearanceSettings.tsx:85
|
||||
#: src/screens/Settings/AppearanceSettings.tsx:135
|
||||
msgid "System"
|
||||
|
||||
@@ -277,7 +277,7 @@ export async function compressImage(
|
||||
async function moveIfNecessary(from: string) {
|
||||
const cacheDir = IS_NATIVE && getImageCacheDirectory()
|
||||
|
||||
if (cacheDir && from.startsWith(cacheDir)) {
|
||||
if (cacheDir && !from.startsWith(cacheDir)) {
|
||||
const to = joinPath(cacheDir, nanoid(36))
|
||||
|
||||
await makeDirectoryAsync(cacheDir, {intermediates: true})
|
||||
|
||||
@@ -141,18 +141,18 @@ function createKlipyApi<Input extends object>(
|
||||
if (!res.ok) {
|
||||
throw new Error('Failed to fetch KLIPY API')
|
||||
}
|
||||
const body: KlipyResponse = await res.json()
|
||||
const body: {next: string; results: Gif[]} = await res.json()
|
||||
return {
|
||||
next: body.next,
|
||||
results: body.data.map(normalizeKlipyGif),
|
||||
results: body.results,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the static URL for a KLIPY GIF preview image.
|
||||
* Currently a pass-through; will route through the bsky proxy once the
|
||||
* backend proxy PR (tango) is deployed.
|
||||
* KLIPY images are served directly from their CDN (static.klipy.com),
|
||||
* unlike Tenor which routes through t.gifs.bsky.app.
|
||||
*/
|
||||
export function klipyStaticUrl(gifUrl: string) {
|
||||
try {
|
||||
@@ -164,78 +164,6 @@ export function klipyStaticUrl(gifUrl: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a native KLIPY gif object onto the Tenor-shaped `Gif` type so
|
||||
* downstream consumers (resolveGif, composer drafts, ExternalEmbed, etc.)
|
||||
* continue to work unchanged.
|
||||
*
|
||||
* NOTE: the exact KLIPY response shape needs to be verified against the
|
||||
* backend proxy once the tango PR is deployed — some fields here are
|
||||
* best-effort based on what's documented today.
|
||||
*/
|
||||
function normalizeKlipyGif(k: KlipyGif): Gif {
|
||||
const toMediaObject = (v: KlipyFileVariant) => ({
|
||||
url: v.url,
|
||||
dims: [v.width, v.height] as [number, number],
|
||||
duration: 0,
|
||||
size: 0,
|
||||
})
|
||||
|
||||
return {
|
||||
id: k.slug,
|
||||
title: k.title ?? '',
|
||||
content_description: k.content_description ?? k.title ?? '',
|
||||
tags: k.tags ?? [],
|
||||
media_formats: {
|
||||
gif: toMediaObject(k.file.hd.gif),
|
||||
tinygif: toMediaObject(k.file.sm.gif),
|
||||
preview: toMediaObject(k.file.sm.gif),
|
||||
},
|
||||
// Tenor-only fields; stub sensibly for KLIPY.
|
||||
created: 0,
|
||||
hasaudio: false,
|
||||
hascaption: false,
|
||||
flags: '',
|
||||
itemurl: k.url ?? '',
|
||||
url: k.url ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
type KlipyFileVariant = {
|
||||
url: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
type KlipyFileFormats = {
|
||||
gif: KlipyFileVariant
|
||||
webp?: KlipyFileVariant
|
||||
mp4?: KlipyFileVariant
|
||||
}
|
||||
|
||||
type KlipyFile = {
|
||||
/** Small/thumbnail size, used in the picker grid */
|
||||
sm: KlipyFileFormats
|
||||
/** Medium size */
|
||||
md: KlipyFileFormats
|
||||
/** Full/large size, used when posting */
|
||||
hd: KlipyFileFormats
|
||||
}
|
||||
|
||||
type KlipyGif = {
|
||||
slug: string
|
||||
title?: string
|
||||
content_description?: string
|
||||
tags?: string[]
|
||||
url?: string
|
||||
file: KlipyFile
|
||||
}
|
||||
|
||||
type KlipyResponse = {
|
||||
next: string
|
||||
data: KlipyGif[]
|
||||
}
|
||||
|
||||
type KlipyAutocompleteResponse = {
|
||||
locale: string
|
||||
results: string[]
|
||||
|
||||
@@ -105,9 +105,8 @@ export function tenorUrlToBskyGifUrl(tenorUrl: string) {
|
||||
|
||||
/**
|
||||
* Returns the appropriate URL for a GIF preview image.
|
||||
* Rewrites Tenor URLs through the bsky proxy; KLIPY URLs pass through
|
||||
* directly (will route through the bsky proxy once the tango backend-proxy
|
||||
* PR is deployed).
|
||||
* Rewrites Tenor URLs through the bsky proxy (t.gifs.bsky.app);
|
||||
* KLIPY URLs pass through directly to their CDN.
|
||||
*/
|
||||
export function gifPreviewUrl(gifUrl: string) {
|
||||
try {
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
-->
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, viewport-fit=cover"
|
||||
/>
|
||||
<!--
|
||||
Preconnect to essential domains
|
||||
|
||||
Reference in New Issue
Block a user