diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-03-05 17:50:20 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-05 09:50:20 -0800 |
commit | f5f02aa4b36ba85c0287324e1654bccaf19cfd5f (patch) | |
tree | 2a8c078c1ffaf7ac734436b4373a2bd4adf840e0 | |
parent | 2d854091b9684ab253a2c117509bf95609a975a1 (diff) | |
download | voidsky-f5f02aa4b36ba85c0287324e1654bccaf19cfd5f.tar.zst |
Add dark mode option to in-app embed snippet dialog (#7377)
* add color theme selection * change chevron direction * change chevron direction again * rm unused ref
-rw-r--r-- | src/components/dialogs/Embed.tsx | 184 |
1 files changed, 125 insertions, 59 deletions
diff --git a/src/components/dialogs/Embed.tsx b/src/components/dialogs/Embed.tsx index ca75b0139..23d050488 100644 --- a/src/components/dialogs/Embed.tsx +++ b/src/components/dialogs/Embed.tsx @@ -1,5 +1,5 @@ -import React, {memo, useRef, useState} from 'react' -import {TextInput, View} from 'react-native' +import {memo, useEffect, useMemo, useState} from 'react' +import {View} from 'react-native' import {AppBskyActorDefs, AppBskyFeedPost, AtUri} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -8,12 +8,19 @@ import {EMBED_SCRIPT} from '#/lib/constants' import {niceDate} from '#/lib/strings/time' import {toShareUrl} from '#/lib/strings/url-helpers' import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import * as TextField from '#/components/forms/TextField' -import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' -import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBrackets} from '#/components/icons/CodeBrackets' +import * as ToggleButton from '#/components/forms/ToggleButton' +import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' +import { + ChevronBottom_Stroke2_Corner0_Rounded as ChevronBottomIcon, + ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon, +} from '#/components/icons/Chevron' +import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets' import {Text} from '#/components/Typography' -import {Button, ButtonIcon, ButtonText} from '../Button' + +export type ColorModeValues = 'system' | 'light' | 'dark' type EmbedDialogProps = { control: Dialog.DialogControlProps @@ -44,11 +51,12 @@ function EmbedDialogInner({ }: Omit<EmbedDialogProps, 'control'>) { const t = useTheme() const {_, i18n} = useLingui() - const ref = useRef<TextInput>(null) const [copied, setCopied] = useState(false) + const [showCustomisation, setShowCustomisation] = useState(false) + const [colorMode, setColorMode] = useState<ColorModeValues>('system') // reset copied state after 2 seconds - React.useEffect(() => { + useEffect(() => { if (copied) { const timeout = setTimeout(() => { setCopied(false) @@ -57,7 +65,7 @@ function EmbedDialogInner({ } }, [copied]) - const snippet = React.useMemo(() => { + const snippet = useMemo(() => { function toEmbedUrl(href: string) { return toShareUrl(href) + '?ref_src=embed' } @@ -75,9 +83,11 @@ function EmbedDialogInner({ // x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x return `<blockquote class="bluesky-embed" data-bluesky-uri="${escapeHtml( postUri, - )}" data-bluesky-cid="${escapeHtml(postCid)}"><p lang="${escapeHtml( - lang, - )}">${escapeHtml(record.text)}${ + )}" data-bluesky-cid="${escapeHtml( + postCid, + )}" data-bluesky-embed-color-mode="${escapeHtml( + colorMode, + )}"><p lang="${escapeHtml(lang)}">${escapeHtml(record.text)}${ record.embed ? `<br><br><a href="${escapeHtml(href)}">[image or embed]</a>` : '' @@ -88,60 +98,116 @@ function EmbedDialogInner({ )}</a>) <a href="${escapeHtml(href)}">${escapeHtml( niceDate(i18n, timestamp), )}</a></blockquote><script async src="${EMBED_SCRIPT}" charset="utf-8"></script>` - }, [i18n, postUri, postCid, record, timestamp, postAuthor]) + }, [i18n, postUri, postCid, record, timestamp, postAuthor, colorMode]) return ( - <Dialog.Inner label="Embed post" style={[a.gap_md, {maxWidth: 500}]}> - <View style={[a.gap_sm, a.pb_lg]}> - <Text style={[a.text_2xl, a.font_bold]}> - <Trans>Embed post</Trans> - </Text> - <Text - style={[a.text_md, t.atoms.text_contrast_medium, a.leading_normal]}> - <Trans> - Embed this post in your website. Simply copy the following snippet - and paste it into the HTML code of your website. - </Trans> - </Text> - </View> - - <View style={[a.flex_row, a.gap_sm]}> - <View style={[a.flex_1]}> - <TextField.Root> - <TextField.Icon icon={CodeBrackets} /> - <TextField.Input - label={_(msg`Embed HTML code`)} - editable={false} - selection={{start: 0, end: snippet.length}} - value={snippet} - style={{}} - /> - </TextField.Root> + <Dialog.Inner label="Embed post" style={[{maxWidth: 500}]}> + <View style={[a.gap_lg]}> + <View style={[a.gap_sm]}> + <Text style={[a.text_2xl, a.font_heavy]}> + <Trans>Embed post</Trans> + </Text> + <Text + style={[a.text_md, t.atoms.text_contrast_medium, a.leading_normal]}> + <Trans> + Embed this post in your website. Simply copy the following snippet + and paste it into the HTML code of your website. + </Trans> + </Text> </View> - <Button - label={_(msg`Copy code`)} - color="primary" - variant="solid" - size="large" - onPress={() => { - ref.current?.focus() - ref.current?.setSelection(0, snippet.length) - navigator.clipboard.writeText(snippet) - setCopied(true) - }}> - {copied ? ( - <> - <ButtonIcon icon={Check} /> - <ButtonText> - <Trans>Copied!</Trans> - </ButtonText> - </> - ) : ( + <View + style={[ + a.border, + t.atoms.border_contrast_low, + a.rounded_sm, + a.overflow_hidden, + ]}> + <Button + label={ + showCustomisation + ? _(msg`Hide customization options`) + : _(msg`Show customization options`) + } + color="secondary" + variant="ghost" + size="small" + shape="default" + onPress={() => setShowCustomisation(c => !c)} + style={[ + a.justify_start, + showCustomisation && t.atoms.bg_contrast_25, + ]}> + <ButtonIcon + icon={showCustomisation ? ChevronBottomIcon : ChevronRightIcon} + /> <ButtonText> - <Trans>Copy code</Trans> + <Trans>Customization options</Trans> </ButtonText> + </Button> + + {showCustomisation && ( + <View style={[a.gap_sm, a.p_md]}> + <Text style={[t.atoms.text_contrast_medium, a.font_bold]}> + <Trans>Color theme</Trans> + </Text> + <ToggleButton.Group + label={_(msg`Color mode`)} + values={[colorMode]} + onChange={([value]) => setColorMode(value as ColorModeValues)}> + <ToggleButton.Button name="system" label={_(msg`System`)}> + <ToggleButton.ButtonText> + <Trans>System</Trans> + </ToggleButton.ButtonText> + </ToggleButton.Button> + <ToggleButton.Button name="light" label={_(msg`Light`)}> + <ToggleButton.ButtonText> + <Trans>Light</Trans> + </ToggleButton.ButtonText> + </ToggleButton.Button> + <ToggleButton.Button name="dark" label={_(msg`Dark`)}> + <ToggleButton.ButtonText> + <Trans>Dark</Trans> + </ToggleButton.ButtonText> + </ToggleButton.Button> + </ToggleButton.Group> + </View> )} - </Button> + </View> + <View style={[a.flex_row, a.gap_sm]}> + <View style={[a.flex_1]}> + <TextField.Root> + <TextField.Icon icon={CodeBracketsIcon} /> + <TextField.Input + label={_(msg`Embed HTML code`)} + editable={false} + selection={{start: 0, end: snippet.length}} + value={snippet} + /> + </TextField.Root> + </View> + <Button + label={_(msg`Copy code`)} + color="primary" + variant="solid" + size="large" + onPress={() => { + navigator.clipboard.writeText(snippet) + setCopied(true) + }}> + {copied ? ( + <> + <ButtonIcon icon={CheckIcon} /> + <ButtonText> + <Trans>Copied!</Trans> + </ButtonText> + </> + ) : ( + <ButtonText> + <Trans>Copy code</Trans> + </ButtonText> + )} + </Button> + </View> </View> <Dialog.Close /> </Dialog.Inner> |