Compare commits

..

4 Commits

Author SHA1 Message Date
keyan c7d926df30 define new env vars in service worker 2024-04-08 17:55:29 -05:00
keyan 81d3212ffb add NEXT_PUBLIC_URL 2024-04-08 17:54:39 -05:00
Ben Allen 5be6df0266
Internal links are not target=_blank by default (#1037)
* feat: internal links are not target=_blank by default

* feat: use <Link>

---------

Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
2024-04-08 16:56:44 -05:00
Felipe Bueno 4633e8eb5e
Allow pasting image from clipboard (#1043)
* form.js: Allow pasting image from clipboard

* remove semicolons

* Check clipboardData.items before continuing

* == -> ===

* Remove semicolons... again =/

* fix Strings must use singlequote

* Ignore DataTransfer no-undef lint error

* new DataTransfer -> new window.DataTransfer()

* add multiple image pasting

---------

Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
2024-04-08 16:31:02 -05:00
14 changed files with 58 additions and 12 deletions

View File

@ -42,6 +42,7 @@ LNWITH_URL=
NEXTAUTH_URL=http://localhost:3000/api/auth
SELF_URL=http://app:3000
PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_URL=http://localhost:3000
LND_CONNECT_ADDRESS=03cc1d0932bb99b0697f5b5e5961b83ab7fd66f1efc4c9f5c7bad66c1bcbe78f02@xhlmkj7mfrl6ejnczfwl2vqik3xim6wzmurc2vlyfoqw2sasaocgpuad.onion:9735
NEXTAUTH_SECRET=3_0W_PhDRZVanbeJsZZGIEljexkKoGbL6qGIqSwTjjI
JWT_SIGNING_PRIVATE_KEY={"kty":"oct","kid":"FvD__hmeKoKHu2fKjUrWbRKfhjimIM4IKshyrJG4KSM","alg":"HS512","k":"3_0W_PhDRZVanbeJsZZGIEljexkKoGbL6qGIqSwTjjI"}

View File

@ -79,7 +79,7 @@ export function getGetServerSideProps (
const { data: { me } } = await client.query({ query: ME })
if (authRequired && !me) {
const callback = process.env.PUBLIC_URL + req.url
const callback = process.env.NEXT_PUBLIC_URL + req.url
return {
redirect: {
destination: `/signup?callbackUrl=${encodeURIComponent(callback)}`

View File

@ -256,6 +256,32 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
}
}, [innerRef, helpers?.setValue, setSelectionRange, onKeyDown])
const onPaste = useCallback((event) => {
const items = event.clipboardData.items
if (items.length === 0) {
return
}
let isImagePasted = false
const fileList = new window.DataTransfer()
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (item.type.indexOf('image') === 0) {
const blob = item.getAsFile()
const file = new File([blob], 'image', { type: blob.type })
fileList.items.add(file)
isImagePasted = true
}
}
if (isImagePasted) {
event.preventDefault()
const changeEvent = new Event('change', { bubbles: true })
imageUploadRef.current.files = fileList.files
imageUploadRef.current.dispatchEvent(changeEvent)
}
}, [imageUploadRef])
const onDrop = useCallback((event) => {
event.preventDefault()
setDragStyle(null)
@ -341,6 +367,7 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
onDragEnter={onDragEnter}
onDragLeave={onDragLeave}
onDrop={onDrop}
onPaste={onPaste}
className={dragStyle === 'over' ? styles.dragOver : ''}
/>)}
</UserSuggest>

View File

@ -21,7 +21,7 @@ export default function Invite ({ invite, active }) {
<CopyInput
groupClassName='mb-1'
size='sm' type='text'
placeholder={`${process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : 'https://stacker.news'}/invites/${invite.id}`} readOnly noForm
placeholder={`${process.env.NEXT_PUBLIC_URL}/invites/${invite.id}`} readOnly noForm
/>
<div className={styles.other}>
<span>{invite.gift} sat gift</span>

View File

@ -14,7 +14,7 @@ const referrurl = (ipath, me) => {
if (!SSR) {
return `${window.location.protocol}//${window.location.host}${path}`
}
return `https://stacker.news${path}`
return `${process.env.NEXT_PUBLIC_URL}${path}`
}
export default function Share ({ path, title, className = '' }) {

View File

@ -178,6 +178,8 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
// If [text](url) was parsed as <a> and text is not empty and not a link itself,
// we don't render it as an image since it was probably a conscious choice to include text.
const text = children[0]
const url = !href.startsWith('/') && new URL(href)
const internalURL = process.env.NEXT_PUBLIC_URL
if (!!text && !/^https?:\/\//.test(text)) {
if (props['data-footnote-ref'] || typeof props['data-footnote-backref'] !== 'undefined') {
return (
@ -189,6 +191,16 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
</Link>
)
}
if (href.startsWith('/') || url.origin === internalURL) {
return (
<Link
id={props.id}
href={href}
>
{text}
</Link>
)
}
return (
// eslint-disable-next-line
<a id={props.id} target='_blank' rel={rel ?? UNKNOWN_LINK_REL} href={href}>{text}</a>
@ -198,7 +210,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
try {
const linkText = parseInternalLinks(href)
if (linkText) {
return <a target='_blank' href={href} rel='noreferrer'>{linkText}</a>
return <Link href={href}>{linkText}</Link>
}
} catch {
// ignore errors like invalid URLs

View File

@ -251,7 +251,7 @@ function HeaderHeader ({ user }) {
</div>
)
const lnurlp = encodeLNUrl(new URL(`https://stacker.news/.well-known/lnurlp/${user.name}`))
const lnurlp = encodeLNUrl(new URL(`${process.env.NEXT_PUBLIC_URL}/.well-known/lnurlp/${user.name}`))
return (
<div className='d-flex mt-2 flex-wrap flex-column flex-sm-row'>
<HeaderPhoto user={user} isMe={isMe} />

View File

@ -31,7 +31,7 @@ export async function lnAddrOptions (addr) {
let protocol = 'https'
if (process.env.NODE_ENV === 'development') {
// support HTTP and HTTPS during development
protocol = process.env.PUBLIC_URL.split('://')[0]
protocol = process.env.NEXT_PUBLIC_URL.split('://')[0]
}
const unexpectedErrorMessage = `An unexpected error occurred fetching the Lightning Address metadata for ${addr}. Check the address and try again.`
let res

View File

@ -8,7 +8,7 @@ export function ensureProtocol (value) {
}
export function isExternal (url) {
return !url.startsWith(process.env.PUBLIC_URL + '/') && !url.startsWith('/')
return !url.startsWith(process.env.NEXT_PUBLIC_URL + '/') && !url.startsWith('/')
}
export function removeTracking (value) {
@ -28,11 +28,12 @@ export function removeTracking (value) {
*/
export function parseInternalLinks (href) {
const url = new URL(href)
const internalURL = process.env.NEXT_PUBLIC_URL
const { pathname, searchParams } = url
// ignore empty parts which exist due to pathname starting with '/'
const emptyPart = part => !!part
const parts = pathname.split('/').filter(emptyPart)
if (parts[0] === 'items' && /^[0-9]+$/.test(parts[1])) {
if (parts[0] === 'items' && /^[0-9]+$/.test(parts[1]) && url.origin === internalURL) {
const itemId = parts[1]
// check for valid item page due to referral links like /items/123456/r/ekzyis
const itemPages = ['edit', 'ots', 'related']

View File

@ -207,6 +207,11 @@ module.exports = withPlausibleProxy()({
'process.env.MEDIA_URL_DOCKER': JSON.stringify(process.env.MEDIA_URL_DOCKER),
'process.env.NEXT_PUBLIC_MEDIA_URL': JSON.stringify(process.env.NEXT_PUBLIC_MEDIA_URL),
'process.env.NEXT_PUBLIC_MEDIA_DOMAIN': JSON.stringify(process.env.NEXT_PUBLIC_MEDIA_DOMAIN),
'process.env.NEXT_PUBLIC_URL': JSON.stringify(process.env.NEXT_PUBLIC_URL),
'process.env.NEXT_PUBLIC_FAST_POLL_INTERVAL': JSON.stringify(process.env.NEXT_PUBLIC_FAST_POLL_INTERVAL),
'process.env.NEXT_PUBLIC_NORMAL_POLL_INTERVAL': JSON.stringify(process.env.NEXT_PUBLIC_NORMAL_POLL_INTERVAL),
'process.env.NEXT_PUBLIC_LONG_POLL_INTERVAL': JSON.stringify(process.env.NEXT_PUBLIC_LONG_POLL_INTERVAL),
'process.env.NEXT_PUBLIC_EXTRA_LONG_POLL_INTERVAL': JSON.stringify(process.env.NEXT_PUBLIC_EXTRA_LONG_POLL_INTERVAL),
'process.env.NEXT_IS_EXPORT_WORKER': 'true'
})
]

View File

@ -10,7 +10,7 @@ export default async ({ query: { username } }, res) => {
}
return res.status(200).json({
callback: `${process.env.PUBLIC_URL}/api/lnurlp/${username}/pay`, // The URL from LN SERVICE which will accept the pay request parameters
callback: `${process.env.NEXT_PUBLIC_URL}/api/lnurlp/${username}/pay`, // The URL from LN SERVICE which will accept the pay request parameters
minSendable: 1000, // Min amount LN SERVICE is willing to receive, can not be less than 1 or more than `maxSendable`
maxSendable: 1000000000,
metadata: lnurlPayMetadataString(username), // Metadata json which must be presented as raw string here, this is required to pass signature verification at a later step

View File

@ -53,7 +53,7 @@ export async function getServerSideProps ({ req, res, query: { id, error = null
return {
props: {
providers: await getProviders(),
callbackUrl: process.env.PUBLIC_URL + req.url,
callbackUrl: process.env.NEXT_PUBLIC_URL + req.url,
invite: data.invite,
error
}

View File

@ -26,7 +26,7 @@ export async function getServerSideProps ({ req, res, query: { callbackUrl, erro
// in the cause of auth linking we want to pass the error back to
// settings
if (error) {
const url = new URL(callbackUrl, process.env.PUBLIC_URL)
const url = new URL(callbackUrl, process.env.NEXT_PUBLIC_URL)
url.searchParams.set('error', error)
callbackUrl = url.pathname + url.search
}

View File

@ -102,7 +102,7 @@ export default function Referrals ({ ssrData }) {
groupClassName='mb-0 w-100'
readOnly
noForm
placeholder={`https://stacker.news/r/${me.name}`}
placeholder={`${process.env.NEXT_PUBLIC_URL}/r/${me.name}`}
/>
</div>
<ul className='py-3 text-muted'>